Kerberos认证原理 分布式 Nginx环境搭建 javascript arrays perl object ipad timer variant sas smtp vue开发文档 nginx视频教程 jquery获取dom对象 新手学c还是java android网络请求 重置hosts 安装python教程 python中for循环的用法 javapackage java接口怎么写 java获取当前线程 java基础框架 java对象序列化 java八大基本数据类型 java格式化日期 java集成开发环境 java函数调用 linux云服务器 忧思华光玉攻略 海鸥浏览器 python输入数字 催眠魔蛙 c4d文字 火萤壁纸下载 ps从入门到精通 五笔字型86版 autocad2004迷你版 php完全自学手册
当前位置: 首页 > 学习教程  > 编程语言

C++进阶教程 - 委托构造函数和继承构造函数

2020/12/5 10:37:34 文章标签:

委托构造函数 什么是委托构造函数? 委托构造函数是由C11引入的新概念,是对C构造函数的改进,允许构造函数使用初始化列表调用同类中的其他构造函数,旨在简化构造函数的书写,提升代码的可维护性,降低代码的…

委托构造函数

什么是委托构造函数?

委托构造函数是由C++11引入的新概念,是对C++构造函数的改进,允许构造函数使用初始化列表调用同类中的其他构造函数,旨在简化构造函数的书写,提升代码的可维护性,降低代码的冗余性。

我们先写个例子感受一下:

class Foo
{
public:
	Foo(): m_nType(4), m_cName('a') { initData(); }
	Foo(int type): m_nType(type), m_cName('a') { initData(); }
	Foo(char c): m_nType(4), m_cName(c) { initData(); }

private:
	void initData() {}
	
private:
	int m_nValue;
	char m_cName;
};

在上面的类定义中,有三个构造函数,从形式上来说,有几个共同点:

  • 使用初始化列表来初始化m_nValue和m_cName这两个成员变量
  • 函数体中都只调用了initData()这个函数。

使用C++11提供的委托构造函数就可以简写为以下形式:

class Foo
{
public:
	Foo(): m_nType(4), m_cName('a') { initData(); }
	Foo(int type): Foo() { m_nType = type; }
	Foo(char c): Foo() { m_cName = c; }

prvate:
	void initData() {}
	
private:
	int m_nValue;
	char m_cName;
};

从这里我们可以看出来委托函数的作用:一个委托函数使用同类中其他构造函数来执行自己的初始化过程,或者说它把自己的一些甚至全部职责委托给了其他构造函数。这也是"委托"二字的由来。

使用委托函数的注意事项:

  • 使用委托函数时,初始化列表中只能包含目标构造函数,而不能包含对成员变量的初始化,只能在函数体中对指定的成员变量进行赋值操作。

  • 不要形成委托环,会导致编译错误。举个例子:

class Foo
{
public:
	Foo(int i) : Foo('c') { type = i; }
	Foo(char c) : Foo(1) { name = c; }

private:
	int type;
	char name;
};

上面的类定义就形成了委托环,也就是委托函数的相互调用,形成交叉的委托关系。

  • 可以使用try…catch结构捕捉目标构造函数throw的异常。示例代码:
#include <iostream>
using namespace std;

class Foo
{
public:
	Foo(int i) try: Foo(i, 'c')
	{
		cout << "start assignment" << endl;
		type = i;
	}
	catch(...)
	{
		cout << "caugth exception" << endl;
	}

private:
	Foo(int i, char c)
	{
		cout << "throw exception" << endl;
		throw 0;
	}

private:
	int type;
	char name;
};

int main()
{
	Foo f(1);
	return 0;
}

在main函数中使用委托构造函数产生对象时,由于采用了try…catch捕捉到了目标构造函数throw出的异常,就不会执行委托函数的函数体部分。

程序的执行结果如下:

throw exception
caugth exception

继承构造函数

什么是继承构造函数?

在C++11之前,子类为了完成基类初始化工作,需要在自己的构造函数的初始化列表中调用父类的构造函数,从而完成构造函数的传递。如果父类有多个构造函数(函数重载),子类也需要编写多个构造函数来分别实现对父类构造函数的调用。

举个例子:

class Base
{
public:
	Base(int va) : m_value(va), m_c('0') {}
	Base(char c) : m_value(0), m_c(c) {}

private:
	int m_value;
	char m_c;
};

class Derived: public Base
{
public:
	Derived(int va) : Base(va) {}
	Derived(char c) : Base(c) {}

public:
	void display() {}
};

书写多个派生类的构造函数只为了传递参数完成基类的初始化,这种方式无疑给程序员带来了不必要的麻烦。在C++11中,推出了继承构造函数概念,可以省去这些麻烦。示例代码如下:

class Base
{
public:
	Base(int va) : m_value(va), m_c('0') {}
	Base(char c) : m_value(0), m_c(c) {}

private:
	int m_value;
	char m_c;
};

class Derived: public Base
{
public:
	using Base::Base; // 使用了继承构造函数,用于自动完成基类的初始化工作

public:
	void display() {}
};

在自动完成基类的初始化工作的同时,继承构造函数还有一个优点:如果一个继承构造函数不被相关代码使用(未使用),则编译器不会为其产生真正的函数代码。

使用继承构造函数的注意事项:

  • 继承构造函数无法初始化派生类数据成员。继承构造函数只是为了初始化基类,如果派生类拥有自己的成员变量,则需要使用就地初始化或者新增构造函数的方式来完成自己的成员函数初始化工作。

  • 基类构造函数拥有默认值会产生多个构造函数版本,且继承构造函数无法继承基类构造函数的默认参数,所有使用带有默认参数构造函数的基类时就必须小心。

      	示例代码:
      	
      	class A
      	{
      	public:
      		A(int a = 3, double b = 4.0) : m_a(a), m_b(b) {}
      		void display() { cout << m_a << " " << m_b << endl; }
      	
      	private:
      		int m_a;
      		double m_b;
      	};
      	
      	class B: public A
      	{
      		public:
      		using A::A;
      	};
      	
      	那么A中的构造函数就会有以下几个版本:
      	
      	A()
      	A(int)
      	A(int,double)
      	A(const A&)
      	
      	B中对应的继承构造函数将会包含如下几个版本:
      	
      	B()
      	B(int)
      	B(int,double)
      	B(const B&)
      	
      	可以看出,参数默认值会导致多个构造函数版本的产生,因此在使用时需要格外小心。
    
  • 在多继承的情况下,继承构造函数会出现"冲突"的情况,因为多个基类中的部分构造函数可能导致派生类中的继承构造函数的函数名、参数相同。

      示例代码:
      
      class A
      {
      public:
      	A(int i) {}
      };
      
      class B
      {
      public:
      	B(int i) {}
      };
      
      class C: public A, public B
      {
      	using A::A;
      	using B::B; // 编译错误,重复定义C(int)
      	C(int i): A(i), B(i) {} // 用显式定义构造函数方式解决冲突
      };
    
  • 如果基类构造函数被声明为私有成员函数,或者派生类时从基类中虚继承的,那么就不能在派生类中定义继承构造函数

  • 一旦使用继承构造函数,编译器就不再为派生类生成默认构造函数了


本文链接: http://www.dtmao.cc/news_show_450285.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?