从一道习题说起
完成程序使得其输出为:
25
86
// An highlighted block
#include <iostream>
using namespace std;
class A{
int a;
public:
A(int m=0):a(m){}
A(A &t){_______}
void show(){cout<<a<<endl;}
void ss(){cout <<11;}
};
class B:public A
{
int b;
public:
B(int m,int n):A(m),b(n){}
B(B &t):_________;
void show(){A::show();cout<<b<<endl;}
void ss(){cout << 22;}
};
int main()
{
B b(25,86),c(b);
c.show();
return 0;
}
- 分析代码可知,A类为基类,B类公有继承自A。A类有私有成员a,B类有私有成员b。
- 需要完成处为两个类的复制构造函数,从子类B开始思考,联想到一般的构造函数需要先在初始化列表中初始化基类对象,再初始化当前类的数据成员,即:
对于复制构造函数同理,但是差别在于复制构造函数的参数为对子类对象的引用。B(int m, int n):A(m), b(n){}
- 还是先初始化基类对象,由此进入基类复制构造函数的编写,可用的只有一个A& t,所以第一条横线处填写:
此处的一个细节是,对于类的私有成员,类的成员函数可以访问,但是类用户无法直接访问,但是在构造函数中,这个规定似乎被打破了,在调用复制构造函数时,使用一个对象的复制构造函数提取另一个对象的数据成员,也就是说在这里类用户直接访问了类的私有数据成员,在这种情况下,如果构造函数有返回值,则可以窃取另一对象的私有数据成员,但是很可惜,成员函数并不具有返回值。a = t.a;
- 接着我们开始写子类对象的复制构造函数,这里唯一可用的参数是B& t,又要先初始化基类对象,所以唯一的选择是:
这里的细节是——A(t),用子类对象给基类引用赋值,符合赋值兼容规则,但是在一般的函数中,指向子类对象的基类的引用或指针也无法访问到基类的私有数据成员,但是在构造函数中可以,这里就是一个例子:B的复制构造函数调用了A的复制构造函数,A的复制构造函数的参数为指向子类对象的基类引用,通过这个引用,可以访问到子类对象的基类对象的私有数据成员,同样,如果有返回功能,构造函数将有机会泄露私有数据,因此构造函数不能有返回值。A(t), b(t.b)