Ihr Verwirrung entsteht durch einen entscheidenden Unterschied zwischen Java und C++.
In Java, wenn Sie schreiben
MyClass var = whatever;
Ihre Variable var
eine Referenz auf das von whatever
zurückgegebene Objekt. In C++ bedeutet diese Syntax jedoch "Erstellen Sie ein neues Objekt vom Typ MyClass
, indem Sie das Ergebnis des Ausdrucks whatever
an einen geeigneten Konstruktor übergeben und das resultierende Objekt in die Variable var
kopieren.
Insbesondere schafft Ihr Code ein neues Objekt vom Typ A
, genannt c
und übergibt ein temporären Standard konstruierten Objekte vom Typ B
seines Copykonstruktor (weil das der einzige Konstruktor ist, das paßt). Da das neu angelegte Objekt vom Typ A
ist, nicht vom Typ B
, wird natürlich A
's Methode foo
aufgerufen. Wenn Sie eine Referenz auf ein Objekt haben möchten, müssen Sie dies explizit in C++ anfordern, indem Sie &
zum Typ hinzufügen. Ein Verweis auf nicht konstante Objekte kann jedoch nicht an Provisorien gebunden werden. Daher müssen Sie auch explizit das Objekt deklarieren, an das Sie binden (oder alternativ einen Verweis auf ein const-Objekt verwenden und Ihre foo
-Elementfunktionen auf const
fixieren, da sie das Objekt ohnehin nicht ändern). So ist die einfachste Version des Codes zu tun, was würden Sie lesen möchten:
// your original definitions of A and B assumed here
B b; // The object of type B
A& c = b; // c is now a *reference* to b
int main() { c.foo(); } // calls B::foo() thanks to polymorphism
jedoch die bessere Version const zu korrigieren, wäre und könnte dann Ihre ursprünglichen Konstruktion verwenden:
#include <iostream>
class A
{
public:
virtual void foo() const // note the additional const here!
{ std::cout << "foo" << std::endl; }
};
class B : public A
{
public:
void foo() const // and also const here
{ std::cout << "overridden foo" << std::endl; }
};
A const& c = B(); // Since we bind to a const reference,
// the lifetime of the temporary is extended to the
// lifetime of the reference
int main() { c.foo(); } //prints overridden foo
(beachten Sie, dass ich jedoch entfernt using namespace std;
weil es eine schlechte Sache zu tun (und Verwendung im Code explizit std::
sowieso, es ist so einfach redundant) ist.
Beachten sie, dass C++ Referenzen aus Java Referenzen, dass nach wie vor unterschiedlich sind sie nicht neu zugewiesen werden können ed; Jede Zuweisung wird stattdessen an das zugrunde liegende Objekt übergeben. Zum Beispiel:
#include <iostream>
class A { public: virtual void foo() const { std::cout << "I'm an A\n"; } };
class B: public A { public: void foo() const { std::cout << "I'm a B\n"; } };
class C: public A { public: void foo() const { std::cout << "I'm a C\n"; } };
B b;
C c;
int main()
{
A& ref = b; // bind reference ref to object b
ref.foo(); // outputs "I'm a B"
ref = c; // does *not* re-bind the reference to c, but calls A::operator= (which in this case is a no-op)
ref.foo(); // again outputs "I'm a B"
}
Wenn Sie das Objekt, das Sie beziehen sich ändern wollen, müssen Sie Zeiger verwenden:
// definitions of A, B and C as above
int main()
{
A* prt = &b; // pointer ptr points to b
prt->foo(); // outputs "I'm a B"
prt = &c; // reassign ptr to point to c
prt->foo(); // outputs "I'm a C"
}
[. Bitte verwenden Sie nicht 'using namespace std;'] (http : //stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) – orlp
Sie müssen auf 'foo()' durch einen 'A *' Zeiger oder 'A &' Bezug zurückgreifen. –
@ πάνταῥεῖ Könntest du dir nicht erklären, was du sagst? Ok, es funktioniert, aber warum gibt es so einen Unterschied? Ich kann das nicht für mich auf eine logische Art erklären ... – stella