Seite 1 von 1

C++ - Verdecken einer virtuellen Funktion

Verfasst: 05.10.2014, 22:51
von Spiele Programmierer
Ich bin heute über ein überraschendes seltenes Problem in C++ gestolpert, wofür ich früher in C# eine einfache Lösung gehabt hätte.
Und zwar geht es darum eine virtuelle Funktion nicht zu überschreiben sondern zu verdecken. Konkret soll folgendes möglich sein...

Code: Alles auswählen

class A
{
public:
    virtual std::uint64_t SomeFunction();
};
class B : public A
{
public:
    std::uint32_t SomeFunction(); //<-Zu beachten: Anderer Rückgabetyp.
    //Kein Ersatz in der VTable. Gibt es eine Instanz vom Typ "B" die in den Typ "A" gecastet ist,
    //soll immernoch die Implementierung von "SomeFunction" in der Basisklasse "A" aufgerufen werden.
};
In C# war das kein Problem, einfach die zweite Funktion in "B" mit "new" kennzeichnen. Gibt es eine Möglichkeit in C++ diese Funktionalität zu erreichen? Einfach auf die naive Weise, wie der Code oben, führt zur Fehlermeldung... "error C2555: 'B::SomeFunction': Der überschreibende virtuelle Funktionsrückgabetyp unterscheidet sich und ist keine 'covariant' von 'A::SomeFunction"
Der Compiler will offensichtlich die Funktion trotz unterschiedlichen Rückgabetyp überschreiben, was natürlich nicht klappt.

Re: C++ - Verschatten einer virtuellen Funktion

Verfasst: 05.10.2014, 23:00
von Helmut
Das geht nicht. Überladene Funktionen dürfen sich nicht ausschließlich im Rückgabetyp unterscheiden.
Wofür brauchst du das denn?

Re: C++ - Verschatten einer virtuellen Funktion

Verfasst: 06.10.2014, 13:12
von Jonathan
Na, du könntest statt RÜckgabewert einen Zeiger oder eine Referenz übergeben um das Ergebnis zu bekommen. Das ist natürlich nicht so schön in der Benutzung, aber wenn du wirklich dringend das Verhalten brauchst, ist es natürlich eine Lösung.

Re: C++ - Verschatten einer virtuellen Funktion

Verfasst: 06.10.2014, 17:31
von Spiele Programmierer
Ich will es auch nicht überladen. Ich will praktisch für "B" genau das Verhalten das es gäbe, wenn kein "virtual" in "A" angegeben wäre. Die Funktion in A ist dann einfach verdeckt. Nicht überladen und auch nicht überschrieben. Das "virtual" ist leider für weitere abgeleiteten Klassen notwendig.

In dem Fall geht es tatsächlich eher um die Benutzung, theoretisch könnte ich der Methode auch einen anderen Namen geben, das fände ich allerdings nicht so nett und ich bin etwas schockiert, dass es dafür tatsächlich keine (offensichtliche) Lösung gibt.

Zur Verwendung:
Es geht einfach darum, dass meine Basisklasse eine Funktionalität anbietet, die technisch 64Bit Integer voraussetzt. (Noch genauer gesagt geht es um meine Stream-Klasse). Nun gibt es eine davon abgeleitete Klasse, die selbst Prinzip bedingt maximal Werte im Bereich von "size_t" zurückgibt. Um einige unnötige Casts bzw. Warnungen im 32Bit Build zu sparen, war meine Idee, einfach die Funktionen mit solchen zu verdecken, die das selbe tun, aber direkt den Typ zurückgeben.

EDIT:
Jonathan hat mich auf eine andere Idee gebracht. Scheint zu funktionieren, vielleicht gibt es aber auch eine direktere Lösung. (Getestet mit Clang & MSVC)

Code: Alles auswählen

class A
{
public:
    virtual std::uint64_t SomeFunction();
};
class B : public A
{
public:
    std::uint32_t SomeFunction(int Unused = 0); //Durch den Parameter versucht der Compiler nicht mehr zu überschreiben...
};

Re: C++ - Verdecken einer virtuellen Funktion

Verfasst: 06.10.2014, 22:23
von dot

Code: Alles auswählen

class A
{
protected:
  virtual std::uint64_t SomeFunction64() { ... }

  friend std::uint64_t SomeFunction(A& a)
  {
    return a.SomeFunction64();
  }
};

class B : public A
{
private:
  std::uint32_t SomeFunction32() { ... }

  friend std::uint32_t SomeFunction(B& b)
  {
    return b.SomeFunction32();
  }
};


A& a = ...;
B b;

auto x = SomeFunction(a); // calls 64 bit version
auto y = SomeFunction(b); // calls 32 bit version

Re: C++ - Verdecken einer virtuellen Funktion

Verfasst: 06.10.2014, 22:34
von dot
Oder per nonvirtual Interface Pattern:

Code: Alles auswählen

class A
{
protected:
  virtual std::uint64_t SomeFunction64() { ... }
  
public:
  std::uint64_t SomeFunction()
  {
    return SomeFunction64();
  }
};

class B : public A
{
private:
  std::uint32_t SomeFunction32() { ... }
  
  std::uint64_t SomeFunction64()
  {
    return SomeFunction32();
  }
  
public:
  std::uint32_t SomeFunction()
  {
    return SomeFunction32();
  }
};

Re: C++ - Verdecken einer virtuellen Funktion

Verfasst: 07.10.2014, 18:27
von Spiele Programmierer
Danke, auch gute Idee.
Werde ich dann wohl so machen. :)