第18 章探讨 C++新标准.新的类功能. 委托构造函数.继承构造函数

第18 章探讨 C++新标准.新的类功能. 委托构造函数.继承构造函数

第18 章探讨 C++新标准.新的类功能. 委托构造函数.继承构造函数


18.3.3 委托构造函数

如果给类提供了多个构造函数,您可能重复编写相同的代码。也就是说,有些构造函数可能需要包含其他构造函数中已有的代码。为让编码工作更简单、更可靠,C++11允许您在一个构造函数的定义中使用另一个构造函数。这被称为委托,因为构造函数暂时将创建对象的工作委托给另一个构造函数。委托使用成员初始化列表语法的变种:

Class Notes{
	int k;
	double x;
	std::string st;
public:
	Notes();
	Notes(int);
	Notes(int,double);
	Notes(int,double,std::string);
}l
Notes::Notes(int kk,double xx,std::string stt):k(kk).x(xx)st(stt)(/*do stuff*/)
Notes::Notes():Notes(0,0.01,"Oh")(/* do other stuff*/}
Notes::Notes(int kk):Notes(kk,0.01,"Ah"){/* do yet other stuff*/}
Notes::Notes( int kk,double xx):Notes(kk, xx,"Uh"){/* ditto*/

例如,上述默认构造函数使用第一个构造函数初始化数据成员并执行其函数体,然后再执行自己的函数体。

18.3.4 继承构造函数

为进一步简化编码工作,C++11提供了一种让派生类能够继承基类构造函数的机制。C++98 提供了一种让名称空间中函数可用的语法:

namespace Box
{
	int fn(int){...}
	int fn(double){...}
	int fn(const char*){...}
}
using Box::fn;

这让函数血的所有重载版本都可用。也可使用这种方法让基类的所有非特殊成员函数对派生类可用。
例如,请看下面的代码:

class C1
{
...
public:
...
	int fn(int j){...}
	double fn(double w){...}
	void fn(constchar*s){...}
};
class C2 :public Cl
{...
public:
...
	using Cl::fn;
	double fn(double){...};
};
...
C2 c2;
int k=c2.fn(3);// uses C1::fn(int)
double z=c2.fn(2.4);//uses C2::fn(double)

C2 中的 using 声明让 C2 对象可使用 C1的三个 ()方法,但将选择 C2 而不是 C1定义的方法 f(double)。C++11将这种方法用于构造函数。这让派生类继承基类的所有构造函数(默认构造函数、复制构造函数和移动构造函数除外),但不会使用与派生类构造函数的特征标匹配的构造函数:

Class BS
{
	int q;
	double w;
public :
	BS():q(0)w(0){}
	Bs(int k):q(k)w(100){}
	Bs(doublex):q(-1)w(x)()
	B0(intk,doublex):q(k)w(x)}void Show()const {std::cout << q <<"," << w<< '\n';}
};
class DR :public BS
{
	short j;
public :
	using BS::BS;
	DR():j(-100)//DR needs its own default constructorDR(double x):BS(2*x),j(int(x)){}
	DR(inti):j(-2)BS(i,0.5*i){void Show()conststd::cout <<i<<"";BS::Show();
}
int main()
DR ol;// use DR()
DR 2(18.81);//use DR(double)instead of Bs(double)
DR o3(101.8);//use Bs(int,double)

由于没有构造函数 DR(int,double),因此创建 DR对象03 时,将使用继承而来的 BS(int,double)。请注意,继承的基类构造函数只初始化基类成员;如果还要初始化派生类成员,则应使用成员列表初始化语法:DR(int i,intk,doublex):j(i),BS(k,x)
管理虚方法:override和final18.3.5
虚方法对实现多态类层次结构很重要,让基类引用或指针能够根据指向的对象类型调用相应的方法,但虚方法也带来了一些编程陷阱。例如,假设基类声明了一个虚方法,而您决定在派生类中提供不同的版本,这将覆盖旧版本。但正如第13章讨论的,如果特征标不匹配,将隐藏而不是覆盖旧版本:

class Action
{
	int a;
public :
	Action(int i=0):a(i){}
	int val()constreturn a;);
	virtual void f(char ch)const{std::cout << val()<< ch << "\n";)
}
:class Bingo :public Action
{
public:
	Bingo(int i=0):Action(i){}
	virtual void f(char *ch)const{std::cout << val()<< ch << "!\n";
}

由于类 Bingo 定义的是f(char*ch)而不是fchar ch),将对 Bingo对象隐藏fchar ch),这导致程序不能使用类似于下面的代码:

Bingo b(10);
b.f('@');// works for Action object, fails for Bingo object

在C++11中,可使用虚说明符override 指出您要覆盖一个虚函数:将其放在参数列表后面。如果声明与基类方法不匹配,编译器将视为错误。因此,下面的Bingo:f()版本将生成一条编译错误消息:

virtual void f(char *ch)const overridefstd::cout << val()<< "!\n";<<ch

例如,在MicrosofVisualC++2010中,出现的错误消息如下:

method with override specifier 'override' did not override anybase class methods

说明符 final 解决了另一个问题。您可能想禁止派生类覆盖特定的虚方法,为此可在参数列表后面加上final。例如,下面的代码禁止Action的派生类重新定义函数):virtual void f(char ch)const final{ std::cout << val() << ch << “\n”;
说明符 override 和 final 并非关键字,而是具有特殊含义的标识符。这意味着编译器根据上下文确定它们是否有特殊含义;在其他上下文中,可将它们用作常规标识符,如变量名或枚举。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值