1

我已经声明了一个具有虚拟打印功能的超类,并且子类继承了超类。我创建了一个子类实例并以两种不同的方式分配给超类。

#include <iostream>

using namespace std;

class Super
{
public:
    Super(){}
    virtual void print()
    {
    cout << "Super class is printing " << endl;
    }
};

class Child: public Super
{
public:
    Child(){}
    void print()
    {
        cout << "Child class printing" << endl;
    }
};

int main()
{
    Child c;
    Super s = c;
    Super &ss = c;
    s.print(); //prints "Super Class is printing
    ss.print(); //prints "Child Class is printing
    return 0;
}

为什么我们没有从这两个打印调用中得到相同的输出?添加引用如何改变行为?

4

2 回答 2

2

is的动态静态类型只是从内部复制子对象的赋值,并且始终表现为.sSupercSupercsSuper

但是,ss它的静态类型为Super,但其动态类型取决于其初始化,在本例中为Child,因此虚拟调度的行为相应。

这种现象称为“对象切片”

于 2013-08-03T18:13:42.553 回答
1

对象切片问题:

如果您采用超类并将其分配给子类的值,则只有属于超类的成员才会被复制(默认赋值运算符行为)。

考虑以下:

#include <iostream>

using namespace std;

class Super {
public:
   int a;
   Super(): a(0) { }
   Super(int _a): a(_a) { }
   virtual void dump() {
        cout << "A is : " << a << std::endl;
   }
};

class Child: public Super {
public: 
   int b;

   Child(int _a, int _b): b(_b), Super(_a) { } 
   virtual void dump() {
        Super::dump();
        cout << "B is : " << b << std::endl;
   }

};

int main() {
    Child c(5, 10);
    Super s;
    s.dump();  // A is 0
    s = c;
    s.dump();  // A is 5 (but there is no B in s 
               // so calling Child::dump would be nonsensical
}

因此,您可以看到,dump将子值分配给父级时调用子级是无意义的;因为在父上下文中没有“b”。

请注意,像这样的语句:c = s;

是无意义的,因为虽然父母是确定性的(孩子是 Super 的类型,所以隐式运算符Super& Super::operator=(const Super&)适用于派生Child类,反之则不正确;即Child& Child::operator=(const Child&)在上下文中没有意义Super

参考问题

好的,所以混淆来自于理解参考变量是什么。引用变量是其初始化对象的同义词。您可以像使用原始变量一样使用引用变量。

在你的情况下:

   ss.print(); 

是相同的

   c.print();

" 要更清楚地看到这一点,请考虑以下代码段:

int foo;
int& bar = foo;

// bar is now a reference to foo so the following will sets foo to 67
bar = 67;
std::cout << foo <<std::endl;
于 2013-08-03T18:14:53.423 回答