作者所说的不良结果是什么



这个例子取自Bruce Eckel的"C++中的思考"第14章"Upcasting and the Copy Constructor"一节。

#include <iostream>
using namespace std;
class Parent
{
    int i;
    public:
    Parent(int ii) : i(ii) { cout << "Parent(int ii)n"; }
    Parent(const Parent& b) : i(b.i) {  cout << "Parent(const Parent&)n"; }
    Parent() : i(0) { cout << "Parent()n"; }
    friend ostream& operator<<(ostream& os, const Parent& b)
            { return os << "Parent: " << b.i << endl; }
};
class Member
{
    int i;
    public:
    Member(int ii) : i(ii) { cout << "Member(int ii)n"; }
    Member(const Member& m) : i(m.i) { cout << "Member(const Member&)n"; }
    friend ostream& operator<<(ostream& os, const Member& m)
            { return os << "Member: " << m.i << endl; }
};
class Child : public Parent
{
    int i;
    Member m;
    public:
    Child(int ii) : Parent(ii), i(ii), m(ii) { cout << "Child(int ii)n"; }
    friend ostream& operator<<(ostream& os, const Child& c)
            { return os << (Parent&)c << c.m << "Child: " << c.i << endl; }
};
int main() {
  Child c(2);
  cout << "calling copy-constructor: " << endl;
  Child c2 = c;
  cout << "values in c2:n" << c2;
}

作者对此代码作出以下评论:

"Child的运算符<<很有趣,因为它呼叫运营商<lt;对于其中的父零件:通过铸造父对象的子对象&(如果改为转换为基类对象你通常会得到不理想的结果):

return os << (Parent&)c << c.m << "Child: " << c.i << endl;

我还运行了这个程序,将上面的指令替换为:

return os << (Parent)c << c.m << "Child: " << c.i << endl;

推进器运行时没有问题,只有一个预期的差异。现在再次调用Parent复制构造函数,将参数c复制到Parent::operator<<()

那么,作者所说的不良结果是什么呢?

问题是,当您将Child硬强制转换为Parent(而不是Parent&)时,您只会将使Child成为Child的所有内容都分割掉。

通常,当您的类具有虚拟函数(通常在类层次结构内)时,您可以并且将(取决于内部布局、继承类的数量等)修改vptr,然后一直向下进入未定义行为的领域。也就是说,在类层次结构中不使用引用(或指针)有效地扼杀了所有神奇的继承机制(也称为多态性)。

这有点像在说dog=平面;-通过使用重新解释强制转换(这就是C风格的强制转换),你可以利用编译器发出的任何警告,因为你是在告诉它闭嘴。

一点切线。。。

经验法则:基类不应该是可复制的,而应该是可克隆的。

实现:禁用Copy Constructor和Copy Assignment Operator,或者(简单地)创建一个纯虚拟方法。

松弛:在没有纯虚拟方法的情况下,使基类复制构造函数和赋值运算符protected更容易警告:这意味着子类现在可以调用其父类的副本,这可能会触发切片问题。

注意:对于C++11,这也适用于移动对应项。

相关内容

  • 没有找到相关文章

最新更新