C++11小特性之一:构造函数的几个改进

继承构造函数

  • C98继承表现

class A{
private:
	int x;
public:  
	A(int i): x(i){}
};
class B:public A{
private:
	int y;
public:
	B(int i): y(i) {}		//编译失败,B这个构造函数中没有调用A的构造函数
	//B(int i):A(i),y(i) {}
};

int main(){
	B b(1); 
}
  • 这意味着基类A中如果没有默认构造函数,那么B中每一个构造函数都需要显示调用一次A构造函数才行,当构造函数很多的时候,会非常不方便
  • C++11的做法
    • 使用using关键字直接使用父类同名函数
    • using最开始是为了让同名不同参数的基类和派生类得以区分,使用using 基类::函数名称会将所有基类中同名函数原封不动的穿透传递给派生类,比如
    class A{
    
    	public: 
    		void print(double x){
    			cout << "A" << endl;
    		}
    		void print(char x){
    			cout << "AA" << endl;
    		}
    	
    	};
    	class B:public A{
    	public:	
    		//using A::print;		//有这句话则会区分传入参数,否则不会
    		void print(int x){
    			cout << "B" << endl;
    		}
    	};
    int main(){
    	B b;
    	b.print(1);
    	b.print(1.8);		//using 输出A, 否则B
    	b.print('X');		// 用了using 输出AA,否则B
    }
    
    • c++11中将此拓展到继承构造函数,如上例子中,使用using A::A,在B中就会继承A中所有的构造函数,从而减少麻烦
    • 继承构造函数的问题
      • 多重继承导致的问题
      		
      	class A{
      		private:
      			int x;
      			int y;
      		public: 
      			A(int i=3, int b = 6): x(i), y(b){}
      	};
      	class B{
      		private:
      			int y;
      		public: 
      			B(int i): y(i) {}
      	};
      		
      	class C: public A,B{
      		int x;
      		public:
      			using A::A;
      			using B::B; 
      			//C(int i): x(i) {} 	//不加这句会报错,因为A,B有同类型的构造函数,加了则可以使用C中的定义
      	};
      int main(){
      		C c(1);		 
      	}
      

委派构造函数

  • C98语句冗余例子
	class info{
		public:
			info():type(1),name('a'){InitRest()};
			info(int i ):type(i),name('a'){InitRest()};
			info(char a):type(1),name(a){InitRest()};
		private:
			void InitRst();
			int type;
			int name;
	};
  • 在上述例子中,三个构造函数统一调用了InitRest();成员函数,造成代码重复
  • c++11使用委派构造函数的概念,重用一个构造函数,从而减少代码冗余(书中的例子不够明显,有时候不同构造函数会调用大量相同的函数,此时就会导致冗余),下例给出了以info()为基准函数的委派构造函数。
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'};		
};
class info{
	public:
		info():into(1,'a') {}
		info(int i):into(i,'a') {}
		info(char e):into(1,e) {}
	private:
		info(int i, int e):type(i), name(e){InitRest()}
		void InitRest(){...}
		int type;
		char name;
};
  • 除了初始化列表之外,上面两种写法的差别
    • 如果InitRest()中,执行的是type+=1,主函数调用的是info(1)
    • 第一个版本中,先使用info()初始化type,此时type=2(初始值加上type+=1),最后又被赋值为1
    • 第二个版本中,使用通用构造函数info()初始化,就没有多次赋值操作,它一开始就将type赋值为1,然后再调用InitRest()执行type+=1,最终type=2
  • 委派构造函数的问题
    • 委托环:没有基准函数,所有构造函数的执行都依赖于其他构造函数,形成了环
    class B{
    	private:
    		int i;
    		char c;
    	public:
    		B():B(2){}
    		B(int i):B('c'){}
    		B(char e):B(2){}
    }
    
  • 使用模板可以构造通用目标(基准)构造函数,更易实现泛型编程
#include<bits/stdc++.h>
using namespace std;
class base{

	template<class T> base(T first, T last):
		l(first, last){}
	list <int> l;
public:
	list<int> getl(){
		return l;
	}
	base(vector<short> &v):
		base(v.begin(), v.end()){}
	base(deque<int> &d):
		base(d.begin(), d.end()){}

};
int main(){
	vector<short> v;
	list<int> l;
	
	for(int i = 1;i<=6;i++)	
		v.push_back(i);
	base b(v);
	for(auto m:b.getl()){
		cout << m << endl;
	} 
}
  • 在基准构造函数中抛出异常,在委派构造函数中仍能捕捉,但是委派构造函数的内容不会执行。
#include<bits/stdc++.h>
using namespace std;
class DCExcept{
public:
	DCExcept(char c)
		try:DCExcept(1,c){
			cout << "Throw an exception" << endl;
		}
		catch(...){
			cout << "Caught" << endl;
		}
private:
	DCExcept(int i, char c):type(i),ch(c){
		cout << "上面没输出,这里输出了" << endl;
		
		throw 0;
	}
	int type;
	char ch;
};
int main(){
	DCExcept d('c');
	system("pause");
}

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值