Why output for this code is Class A I expected to see "Class AAA"
#include <iostream>
using namespace std;
class A
{
public:
A(){}
virtual int Method1(int a, int b){cout << "Class A" << endl; return a+b; }
};
class AA:public A
{
public:
AA(){}
int Method1(int a, int b){cout << "Class AA" << endl; return a*b;}
};
class AAA:public A
{
public:
AAA(){}
int Method1(int a, int b){cout << "Class AAA" << endl; return a/b;}
};
class B
{
public:
B(){}
B(A a):obj(&a){}
int Method2(int a, int b){ return obj->Method1(a,b);}
private:
A *obj;
};
int main() {
A *a = new AAA();
B *b = new B(*a);
b->Method2(2,1);
return 0;
}
I have new AAA object passed to class B and assigned to *obj. What is wrong with this ? Best Regards,
答案 0 :(得分:2)
You are slicing the object that is passed to the B()
constructor, so all B
sees is an instance of A
and not an instance of AAA
.
Polymorphism only works when you access a derived object by pointer/reference so the full vtable of virtual methods is accessible. That also includes when passing derived objects around. If you pass a derived class to a base class variable/parameter by value, you will slice the object, and the variable/parameter will only have access to the base class vtable entries.
So you need to change B
accordingly, either like this:
class B
{
public:
B() : obj(0) {} // <-- every constructor needs to initialize members!
B(A *a) : obj(a) {} // <-- accept A by pointer
int Method2(int a, int b) { return (obj) ? obj->Method1(a,b) : 0; }
private:
A *obj;
};
int main() {
A *a = new AAA();
B *b = new B(a); // <-- AAA passed by A* pointer
b->Method2(2,1);
// don't forget these
delete b;
delete a;
return 0;
}
Or this:
class B
{
public:
B() : obj(0) {} // <-- every constructor needs to initialize members!
B(A &a) : obj(&a) {} // <-- accept A by reference
int Method2(int a, int b) { return (obj) ? obj->Method1(a,b) : 0; }
private:
A *obj;
};
int main() {
A *a = new AAA();
B *b = new B(*a); // <-- AAA passed by A& reference
b->Method2(2,1);
// don't forget these
delete b;
delete a;
return 0;
}
Or even this:
class B
{
public:
// <-- note: no default constructor!
B(A &a) : obj(a) {} // <-- accept A by reference
int Method2(int a, int b) { return obj.Method1(a,b); }
private:
A &obj;
};
int main() {
A *a = new AAA();
B *b = new B(*a); // <-- AAA passed by A& reference
b->Method2(2,1);
// don't forget these
delete b;
delete a;
return 0;
}
In any case, note that A
needs a virtual destructor so derived destructors can get called correctly when delete
is called on a base class A*
pointer or A&
reference:
class A
{
public:
...
virtual ~A() {} // <-- add this
...
};
If you are using C++11 or later, you should use std::unique_ptr
and std::shared_ptr
instead of raw pointers, let the compiler handle the (de)allocations for you:
#include <memory>
class B
{
public:
B(std::shared_ptr<A> &a) : obj(a) {}
int Method2(int a, int b) { return obj->Method1(a,b); }
private:
std::shared_ptr<A> obj;
};
int main() {
std::shared_ptr<A> a(new AAA);
std::unique_ptr<B> b(new B(a));
// or: if you are using C++14 or later:
/*
std::shared_ptr<A> a = std::make_shared<AAA>();
std::unique_ptr<B> b = std::make_unique<B>(a);
*/
b->Method2(2,1);
return 0;
}