一、多继承下的调用研究
根据上述的模型当中, 我们可以构建出其构造函数的调用顺序
Point(x, y);
Point3d(x, y, z);
Vertex(x, y, z);
Vertex3d(x, y, z);
源代码:
class Point
{
public:
Point(float x = 0.0, float y = 0.0) :_x(x), _y(y){ size(); };
Point(const Point&);
Point& operator=(const Point&);
virtual~Point(){}
virtual void size(){ print(); cout << "Point size: " << sizeof(Point) << endl; }
virtual void print(){ cout << "This is Point. "; }
protected:
float _x, _y;
};
class Point3d :virtual public Point
{
public:
Point3d(float x = 0.0, float y = 0.0, float z = 0.0)
:Point(x, y), _z(z){
size();
}
Point3d(const Point3d& rhs)
:Point(rhs), _z(rhs._z){}
virtual~Point3d(){}
Point3d& operator=(const Point3d&);
virtual void size(){ print(); cout << "Point3d size: " << sizeof(Point3d) << endl; }
void print(){ cout << "This is Point3d. "; }
protected:
float _z;
};
class Vertex :public virtual Point
{
public:
Vertex(float x = 0.0, float y = 0.0, float t = 0.0)
:Point(x, y), _t(t){
size();
}
Vertex(const Vertex& rhs)
:Point(rhs), _t(rhs._t){}
virtual~Vertex(){}
Vertex& operator=(const Vertex&);
virtual void size(){ print(); cout << "Vertex size: " << sizeof(Vertex) << endl; }
void print(){ cout << "This is Vertex. "; }
protected:
float _t;
};
class Vertex3d :public Point3d, public Vertex
{
public:
Vertex3d(float x = 0.0, float y = 0.0, float z = 0.0)
:Point3d(x, y, z), Vertex(x, y, z){
size();
}
Vertex3d(const Vertex3d& rhs)
:Point3d(rhs), Vertex(rhs){}
virtual~Vertex3d(){}
Vertex3d& operator=(const Vertex&);
virtual void size(){ print(); cout << "Vertex3d size: " << sizeof(Vertex3d) << endl; }
void print(){ cout << "This is Vertex3d. "; }
};
运行结果如下:
结果分析:
从结果中可以得出结论, 在构造函数中调用成员函数, 无论是直接调用还是虚化后在调用, 都取决于他正在构造的对象, 与其他任何关系无关。
修改方案一:
Vertex3d(float x = 0.0, float y = 0.0, float z = 0.0)
:Point3d(x, y, z), Vertex(x, y, z){
Point*p = new Point;
p->print(); size();
}
运行结果:
结果分析:
证明了其调用词序词序是根据构造模型构造顺序调用的
修改方案二:
Vertex3d(float x = 0.0, float y = 0.0, float z = 0.0)
:Point3d(x, y, z), Vertex(x, y, z){
Point*p = new Point3d; p->print(); size();
}
结果分析:
在构造函数当中, 子类对象的调用机制
修改方案三:
Vertex3d(float x = 0.0, float y = 0.0, float z = 0.0)
:Point3d(x, y, z), Vertex(x, y, z){
Point*p = new Vertex3d; p->print(); size();
}
在该代码当中如果运行, 因为构造函数的调用机制, 将会产生死循环
二、总结
1、vptr的初始化总是在基类构造函数调用操作之后, 在程序员提供的代码调用之前或者是初始化列表所列的成员初始化操作之前。
2、初始化列表所列的成员初始化操作之前设置vptr, 是为了防止以免有虚函数在构造函数中调用出错。
3、 在构造函数中调用成员函数, 无论是直接调用还是虚化后在调用, 都取决于他正在构造的对象, 与其他任何关系无关。