C++ 11——继承和委派构造函数

本文介绍了C++11中的两种构造函数改进:继承构造函数和委派构造函数。继承构造函数允许派生类通过using声明直接使用基类的构造函数,减少了重复代码。委派构造函数则是让一个构造函数在内部调用另一个构造函数,避免重复编写初始化逻辑。然而,需要注意的是,委派构造函数不能与初始化列表一起使用,并且应避免形成委托环,否则会导致编译错误。
摘要由CSDN通过智能技术生成

继承构造函数

C++ 中自定义类型——类,是C++ 面向对象的基石。类具有可派生性,派生类可以自动获得基类的成员变量和接口。不过基类的非虚函数则无法再被派生类使用了。

如果派生类 要使用基类的构造函数,同城需要在构造函数中显示声明,但是这也带来一个问题:有的时候,我们的基类可能拥有数量众多的不同版本的构造函数,其派生类去构造基类的时候就需要写大量的“透传”构造函数。

struct A
{
	A(int i){}
	A(double d,int i){}
	A(float f,int i, const char* c){}
}

struct B: A
{ 
	B(int i):A(i){}
	B(double d,int i):A(d,i){}
	B(float f,int i,const char* c):A(f,i,c){}	
};

可以看到,这样写很累而且非常的不银杏。事实上,在C++中已经有了一个好用的规则,就是如果派生类要使用基类的成员函数的话,可以通过using声明来完成。

#include <iostream>
using namespace std;

struct Base
{
	void f(double i){cout<<"base:"<<i<<endl;}
};

struct Derived: Base
{
	using Base::f;
	void f(int i){cout<<"derived:"<<i<<endl;}
};

int main()
{
	Base b;
	b.f(4.5);		//base:4.5

	Derived d;
	d.f(4.5);		//base:4.5
};

这里我们使用using声明,这样派生类中就拥有了两个版本的重载函数 f 。

在C++ 11中,这个想法被扩展到了构造函数上,子类可以通过使用using声明来声明继承基类的构造函数。

struct A
{
	A(int i){}
	A(double d,int i){}
	A(float f,int i, const char* c){}
};

struct B: A
{
	using A::A;		//继承构造函数 
};

更为精巧的是,C++ 11标准继承够着函数被设计为跟派生类中各种类默认函数一样,是隐式声明的。这意味着一个继承构造函数不被相关的代码使用,编译器就不会为其产生真正的函数代码。

委派构造函数

与继承构造函数类似,委派构造函数也是C++ 11中对C++的构造函数的一项改进,其目的也是为了减少程序员书写构造函数的时间

//不使用委派构造函数
class Info
{
public:
	Info():type(1),name('a'){InitRest();}
	Info(int i):type(i),name('a'){InitRest();}
	Info(char e):type(1),name(e){InitRest();}

private:
	void InitRest(){...}
	int type;
	char name;
};

//成员初始化方式
class Info
{
public:
	Info() {InitRest();}
	Info(int i):type(i) {InitRest();}
	Info(char e):name(e) {InitRest();}

private:
	void InitRest(){...}
	int type{1};
	char name{'a'};
};

我们可以看到,这两种写法使得代码越来越精简,不过每个函数还是需要写一遍InitRest()

那么如何去解决这个问题呢?看如下代码:

	Info() {InitRest();}
	Info(int i):type(i) {this->Info();}
	Info(char e):name(e) {this->Info();}

但是这个也有问题:一般的编译器都会阻止this->Info()的编译。所以,我们可以写一个更有“黑客精神”的版本:

//这个代码有危险嗷
	Info() {InitRest();}
	Info(int i):type(i) {new (this) Info();}
	Info(char e):name(e) {new (this) Info();}

但是有了C++ 11,我们duck不必这样,直接使用委派构造函数的方法即可:

class Info
{
public:
	Info() {InitRest();}
	Info(int i):Info() {type = i;}
	Info(char e):Info() {name = e}

private:
	void InitRest(){...}
	int type{1};
	char name{'a'};
}

我们可以看到,这里我一改常态,在函数体内给typename两个变量赋值。这是因为,在C++ 11中构造函数不能同时“委派”和使用初始化列表,所以如果委派构造函数要给变量赋初值,初始化代码必须放在函数体中。

但是要注意一个问题:在构造函数比较多的时候,我们可能不止有一个委派构造函数,而一些目标构造函数很可能也是委派构造函数,这样一来,我们就可能在委派构造函数中形成链状的委派构造关系

class Info
{
public:
	Info():Info(1,'a') {}
	Info(int i):Info(i,'a') {}
	Info(char e):Info(1,e) {}

private:
	Info(int i,char e):type(i),name(e) {...}
	int type;
	char name;
}

但是,这种情况往往又容易产生委托环

struct Rule2
{
	int i,c;
	Rule2():Rule2(2){}
	Rule2(int i):Rule2('c'){}
	Rule2(char c):Rule2(2){}
}

这里Rule2(int i),Rule2(char c)两个构造函数相互委托,形成环状,会造成编译错误。

参考文献

[1] IBM XL编译器中国开发团队.深入理解C++11.机械工业出版社.2013.06.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shenmingik

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值