我有代码:
class A{ //base class
public:
virtual std::string getString(){return "class A";}
};
class B: public A{
public:
std::string getString() {return "it is B class";}
};
class C{
public:
C(){
B b;
a = b;
}
std::string test() {return a.getString();}
private:
A a;
};
int main()
{
C c;
std::cout << c.test();
return 0;
}
c.test()说“A类”,但我如何从B类调用方法getString()而不是A?
谢谢!
答案 0 :(得分:7)
问题是,您的B
对象在分配给A
对象时会被切片。这是因为您按值分配,而不是通过引用或指针分配。既然你像这样声明了a
A a;
在作业a = b
期间发生的事情是b
的实际状态被复制到a
。但是,由于a
是值对象,因此只复制对象A
的{{1}}部分,并且其“B-ness”完全丢失!
为了避免这种情况,你需要将b
声明为指针类型,如其他人所建议的那样(引用也可以,但是你需要大大改写你的例子,因为你不能分配给引用,只初始化它们)。如果a
是指针(a
),则作业A*
会使a = b
指向由a
表示的对象,该对象仍为b
因此,您将观察到您期望的多态行为。但是,在这种情况下,您必须确保B
在退出构造函数后仍保持活动状态 - 否则您将留下悬空引用,这会导致未定义的行为(阅读:在被解除引用时,你不想发生的坏事。
由于@Nawaz已经显示了指针示例,我将使用引用给出另一个:
b
答案 1 :(得分:5)
你需要这样实现:
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
这将从B类调用getString()
而不是A。
您尝试做的事情称为“动态多态”,它是通过类型基类的指针(或 reference )实现的({{1} }),但指针指向派生类类型的对象(A
)。
答案 2 :(得分:1)
由于您的成员a
不是A*
,因此它是A
个实例。因此,您只需将A
部分B
分配给变量a
。如果您将a
转换为A*
,您将获得预期的结果。
答案 3 :(得分:1)
您切片因此无效。 a
是A
,不是B
。
要处理类成员变量,必须是指针或引用。
作为指针
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
作为参考
class C{
public:
C() : a( *(new B) )
{
}
std::string test() {return a.getString();}
private:
A &a;
};
当然我的代码产生了泄漏,但是可以使用虚函数。