关于data slicing一个问题,讨论下吧:)
#include <iostream>
using namespace std;
class A
{
public:
A(){cout<<"bbb"<<endl;}
A(const A &) {cout<<"aaa"<<endl;}
virtual void prin(){cout<<"a"<<endl;}
~A(){cout<<"end"<<endl;}
};
class B:public A
{
public:
B(){}
virtual void prin(){cout<<"b"<<endl;}
};
int main()
{
B a;
((A)a).prin();
a.prin ();
return 0;
}
运行结果是
bbb
aaa
a
end
b
end
请问为什么会产生一个调用缺省构造函数的A的对象,是语法分析的问题还是data slicing产生的结果。
问题点数:100、回复次数:3Top
1 楼xueweizhong(薛卫忠)回复于 2003-11-02 20:45:11 得分 40
class B:public A
{
public:
B(){}
^^^^^
等价于 B() : A() {}
导致 B a;
构造A基类子对象时导致A::A()被调用,
所以程序一开始就打印了
bbbbTop
2 楼daizh()回复于 2003-11-02 20:50:32 得分 30
看完下面的解释你就明白了。
这实质是“类的构造函数调用顺序是什么?”
如果一个类有多个基类,基类的构造函数在继承类的构造函数之前被调用。基类的构造函数以被声明的顺序被调用。下面是一个例子:
class Y {...}
class X : public Y {...}
X one;
构造函数的调用顺序是下面的顺序:
Y(); // 基类的构造函数
X(); // 继承类的构造函数
对于多基类的情况,下面是一个例子:
class X : public Y, public Z
X one;
构造函数以声明的次序调用。
Y(); // 基类构造函数首先被调用
Z();
X();
虚基类的构造函数在任何非虚基类构造函数前调用。如果构造中包括多个虚基类,它们的调用顺序以声明顺序为准。如果虚类是由非虚类派生而来,那非虚类的构造函数要先被调用。下面是一个例子:
class X : public Y, virtual public Z
X one;
调用顺序如下:
Z(); // 虚基类初始化
Y(); // 非虚基类
X(); // 继承类
下面是一个复杂的例子:
class base;
class base2;
class level1 : public base2, virtual public base;
class level2 : public base2, virtual public base;
class toplevel : public level1, virtual public level2;
toplevel view;
构造函数调用顺序如下:
base(); // 虚基类仅被构造一次
base2();
level2(); // 虚基类
base2();
level1();
toplevel();
如果类继承中包括多个虚基类的实例,基类只被初始化一次。
Top
3 楼magicblue(小飞侠)回复于 2003-11-02 21:20:31 得分 30
运行过程为:
B a;
要构造a,首先要先构造B的基类A的部分,调用A的构造函数
输出 bbb
((A)a).prin();
进行C风格的类型转换,把a从B类型转换到A类型,调用A的拷贝构造函数(参数为a,这个时候才是data slicing,a的B类型信息部分被sliced)
输出 aaa
并生成一个临时变量,类型为A,并调用这个临时变量的prin(),
输出 a
第二句语句结束,临时变量自动被析构
输出
end
a.prin ();
这个a是最先构造的,不是临时变量
输出 b
程序结束,a被析构
输出 end
这就是整个程序的执行过程Top




