码迷,mamicode.com
首页 > 编程语言 > 详细

【C/C++】【类和对象】多重继承和虚继承

时间:2020-07-23 01:42:32      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:std   其他   不能   通过   定义   value   类构造   成员   移动   

继承的构造函数

  • 一个类只继承其直接基类的构造函数,默认/拷贝/移动构造函数是不能被继承的;

  • 继承Father的构造函数

    using Father::Father; 
    //继承Father的构造函数 using让某个名字在当前的作用域可见;
    //编译器遇到这条代码的时候,会把基类的每个构造函数都生成一个与之对应的派生类构造函数
    
  • 如果基类A的构造函数有默认参数的话,那么编译器遇到这种using A::A的时候,就会帮咱们在派生类B中构造出多个构造函数来;

    1. 第一个构造函数时带有所有参数的构造函数;
    2. 其余的构造函数,每个分别省略掉一个默认参数;
    //示例:
    Son(int i, int j, int k = 5) :Father(i, j, k){};
    Son(int i, int j, int k):Father(i,j,k){};
    Son(int i, int j):Father(i,j){};
    
  • 如果基类含多个构造函数,则多数情况下,派生类会继承所有这些构造函数,但如下情况例外:

    1. 如果在派生类中定义的构造函数与基类构造函数有相同的参数列表,那么从基类中继承来的构造函数会被你在派生类中定义的覆盖掉,相当于只继承了一部分构造函数;
    2. 默认/拷贝/移动构造函数是不会被继承的;
    3. 如果子类,只含有using Father::Father从Father继承来的构造函数的话,那么编译器会给它合成默认的构造函数;
#include <iostream>
using namespace std;

class Father
{
public:
	Father(int i, int j, int k)
	{

	}
};

class Son : public Father
{
public:
	using Father::Father; //继承Father的构造函数 using让某个名字在当前的作用域可见;
	//编译器遇到这条代码的时候,会把基类的每个构造函数都生成一个与之对应的派生类构造函数

};

int main()
{
	Son son(3, 4, 5);
}

多重继承

从多个父类产生出子类,多重继承;

多重继承概述

#include <iostream>
using namespace std;

class Base
{
public:
	Base(int i) :m_value_base(i) {};
public:
	int m_value_base;

	virtual ~Base()
	{

	}

	void my_info()
	{
		cout << m_value_base << endl;
	}
};


class Father_A: public Base
{
public:
	Father_A(int i) :Base(i), m_value_a(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{

	};

	virtual ~Father_A()
	{

	}

	void my_info()
	{
		cout << m_value_a << endl;
	}
public:
	int m_value_a;
};


class Father_B
{
public:

	Father_B(int i):m_value_b(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{

	};

	virtual ~Father_B()
	{

	}

	void my_info()
	{
		cout << m_value_b << endl;
	}
public:
	int m_value_b;

};

//class默认是私有继承
//struct默认是共有继承
class Son :public Father_A, public Father_B
{
public:
	Son(int i, int j, int k) :Father_A(i), Father_B(j), m_value_c(k)
	{

	}

	virtual ~Son()
	{

	}

	void my_info_c()
	{
		cout << m_value_c << endl;
		Father_A::my_info();  //调用父类Father_A的同名函数
		Father_B::my_info(); //调用父类Father_B的同名函数
		
	}
public:
	int m_value_c;
};

int main()
{
	Son son(10, 20, 50);
	//多重继承的二义性问题
	//1. 通过作用域来解决
	son.Father_A::my_info(); //增加作用域,明确告诉系统调用的是父类A还是父类B的成员函数
	//派生类会包含每个基类的子对象

}

静态成员变量

静态成员属于类,不属于对象;

为了能够使用,需要定义静态成员变量;如果代码中不用该静态变量,可以不定义;如果用到该静态变量,可以定义;否则,链接出错;

#include <iostream>
using namespace std;

class Base
{
public:
	Base(int i) :m_value_base(i) {};
public:

	virtual ~Base()
	{

	}

	void my_info()
	{
		cout << m_value_base << endl;
	}
public:
	int m_value_base;
	static int m_static;
};

int Base::m_static = 5;


class Father_A: public Base
{
public:
	Father_A(int i) :Base(i), m_value_a(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{

	};

	virtual ~Father_A()
	{

	}

	void my_info()
	{
		cout << m_value_a << endl;
	}
public:
	int m_value_a;
};


class Father_B
{
public:

	Father_B(int i):m_value_b(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{

	};

	virtual ~Father_B()
	{

	}

	void my_info()
	{
		cout << m_value_b << endl;
	}
public:
	int m_value_b;

};

//class默认是私有继承
//struct默认是共有继承
class Son :public Father_A, public Father_B
{
public:
	Son(int i, int j, int k) :Father_A(i), Father_B(j), m_value_c(k)
	{

	}

	virtual ~Son()
	{

	}

	void my_info_c()
	{
		cout << m_value_c << endl;
		Father_A::my_info();  //调用父类Father_A的同名函数
		Father_B::my_info(); //调用父类Father_B的同名函数
		
	}
public:
	int m_value_c;
};

int main()
{
	//派生类会包含每个基类的子对象
	Base::m_static = 1; 
	Father_A::m_static = 2;
	Son::m_static = 3;

	Son son(10, 20, 30);
	son.m_static = 15;
}

派生类构造函数和析构函数

  1. 构造一个派生类对象将同时构造并初始化所有基类子对象;
  2. 派生类的构造函数初始化列表只初始化它的直接基类,每个类的构造函数都负责初始化它的直接基类,就会让所有类都初始化;
  3. 派生类构造函数初始化列表将实参分别传递给每个直接基类;基类的构造顺序跟派生列表(继承的顺序 )中基类的出现顺序保持一致;
  4. 析构函数的调用顺序与构造函数的顺序完全相反;

显示的初始化基类和隐式的初始化基类

  • 隐式的初始化基类: 派生类的构造函数初始化列表中没有调用带参数的基类构造函数,而是调用的基类的默认构造函数来实现基类的初始化;
#include <iostream>
using namespace std;

class Base
{
public:
	Base(int i) :m_value_base(i) 
	{
		cout << "Base构造函数执行" << endl;
	};
public:

	virtual ~Base()
	{
		cout << "Base析构函数执行" << endl;
	}

public:
	int m_value_base;

};

class Father_A: public Base
{
public:
	Father_A(int i) :Base(i), m_value_a(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{
		cout << "Father_A构造函数执行" << endl;
	};

	virtual ~Father_A()
	{
		cout << "Father_A析构函数执行" << endl;
	}


public:
	int m_value_a;
};


class Father_B
{
public:

	Father_B(int i):m_value_b(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{
		cout << "Father_B构造函数执行" << endl;
	};

	virtual ~Father_B()
	{
		cout << "Father_B析构函数执行" << endl;
	}


public:
	int m_value_b;

};

//class默认是私有继承
//struct默认是共有继承
class Son :public Father_A, public Father_B
{
public:
	Son(int i, int j, int k) :Father_A(i), Father_B(j), m_value_c(k)
	{
		cout << "Son构造函数执行" << endl;
	}

	virtual ~Son()
	{
		cout << "Son析构函数执行" << endl;
	}


public:
	int m_value_c;
};

int main()
{
	Son son(10, 20, 30);
}

从多个父类继承构造函数

如果一个类从它的基类中继承了相同的构造函数,这个类必须为该构造函数定义它的自己的版本;
子类要定义同参数的构造函数的自己的版本;

#include <iostream>
using namespace std;

class Father_A
{
public:
	Father_A(int tv) {};
};
class Father_B
{
public:
	Father_B(int tv) {};
};

class Son :public Father_A, public Father_B
{
	using Father_A::Father_A;//继承Father_A的构造函数   Son(int tv):Father_A(tv){}
	using Father_B::Father_B;//继承Father_B的构造函数   Son(int tv):Father_B(tv){}
	
    Son(int tv) :Father_A(tv), Father_B(tv) {};

};

int main()
{

}

类型转换

基类指针可以指向一个派生类对象:编译器隐式执行这种派生类到基类的转换,转换成功的原因是每个派生类对象都包含一个基类对象部分;所以基类的引用或者指针是可以绑定到基类对象这部分;

上述对于多重继承同样成立;

#include <iostream>
using namespace std;

class Base
{
public:
	Base(int i) :m_value_base(i) 
	{
		cout << "Base构造函数执行" << endl;
	};
public:

	virtual ~Base()
	{
		cout << "Base析构函数执行" << endl;
	}

public:
	int m_value_base;

};

class Father_A: public Base
{
public:
	Father_A(int i) :Base(i), m_value_a(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{
		cout << "Father_A构造函数执行" << endl;
	};

	virtual ~Father_A()
	{
		cout << "Father_A析构函数执行" << endl;
	}


public:
	int m_value_a;
};


class Father_B
{
public:

	Father_B(int i):m_value_b(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{
		cout << "Father_B构造函数执行" << endl;
	};

	virtual ~Father_B()
	{
		cout << "Father_B析构函数执行" << endl;
	}


public:
	int m_value_b;

};

//class默认是私有继承
//struct默认是共有继承
class Son :public Father_A, public Father_B
{
public:
	Son(int i, int j, int k) :Father_A(i), Father_B(j), m_value_c(k)
	{
		cout << "Son构造函数执行" << endl;
	}

	virtual ~Son()
	{
		cout << "Son析构函数执行" << endl;
	}


public:
	int m_value_c;
};


int main()
{
	Base* base = new Son(1, 2, 3);
	Father_A* fa = new Son(1, 2, 3);
	Father_B* fb = new Son(1, 2, 3);


	Son son(10 ,20, 30);
	Base b(son);
}

虚基类,虚继承

派生列表中,同一个基类只能出现一次,但是如下两种情况例外;

  1. 派生类可以通过它的两个直接基类分别继承同一个间接基类;

  2. 直接继承某个基类,然后通过另一个基类间接继承

虚基类和虚继承

  • 无论这个类在继承体系中出现多少次,派生类中,都只会包含唯一一个共享的虚基类字内容;不会出现访问不明确的问题;
  • 虚继承只是对孙子类有意义,对孙子类的直接基类没有意义;例Son继承Father_A和Father_C,Father_A和Father_C继承Base;那么Father_A和Father_B虚继承Base,对Son有意义,避免它间接继承Base两次;
  • 虚继承:表示后续从本类派生的类应该共享虚基类Base的同一份实例;
  • 虚继承之后:虚基类的初始化使用孙子类;

说明

  • 现在是Son类初始化虚基类,如果Son有了子类,那么由Son的子类初始化虚基类;虚基类是由最底层的派生类来初始化;
  • 初始化顺序:先初始化虚基类,然后按照派生列表中出现的顺序来初始化其他类;多个虚基类的话,按照派生列表中直接基类往回追溯,看是否这些直接基类中是否含有虚基类,反正是先追溯到哪个,先构造那个虚基类;析构顺序和构造顺序相反;
#include <iostream>
using namespace std;

class Base
{
public:
	Base(){}
	Base(int i) :m_value_base(i) 
	{
		cout << "Base构造函数执行" << endl;
	};
public:

	virtual ~Base()
	{
		cout << "Base析构函数执行" << endl;
	}

public:
	int m_value_base;

};

class Father_A: virtual public Base //virtual可以和public互换位置
{
public:
	Father_A(int i) :Base(i), m_value_a(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{
		cout << "Father_A构造函数执行" << endl;
	};

	virtual ~Father_A()
	{
		cout << "Father_A析构函数执行" << endl;
	}


public:
	int m_value_a;
};

class Father_C : virtual public Base
{
public:

	Father_C(int i) :Base(i), m_value_c(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{
		cout << "Father_C构造函数执行" << endl;
	};

	virtual ~Father_C()
	{
		cout << "Father_C析构函数执行" << endl;
	}


public:
	int m_value_c;

};



class Father_B
{
public:

	Father_B(int i):m_value_b(i) //每个子类的构造函数,负责解决自己父类的初始化问题
	{
		cout << "Father_B构造函数执行" << endl;
	};

	virtual ~Father_B()
	{
		cout << "Father_B析构函数执行" << endl;
	}


public:
	int m_value_b;

};

//class默认是私有继承
//struct默认是共有继承
class Son :public Father_A, public Father_B, public Father_C
{
public:
	//虚基类的时候,孙子初始化爷爷
	Son(int i, int j, int k) :Base(i), Father_A(i), Father_B(j), Father_C(k), m_value_c(k)
	{
		cout << "Son构造函数执行" << endl;
	}

	virtual ~Son()
	{
		cout << "Son析构函数执行" << endl;
	}


public:
	int m_value_c;
};


int main()
{
	Son son(10 ,20, 30);
	//son间接继承了Base两次,导致Base构造了两次;
	//son.m_value_base = 10; 两个m_value_base, 二义性 
}

总结

  • 不太提倡使用多重继承;简单,不容易出现二义性,使用多重继承;
  • 使用单一继承能解决的尽量不要用多重继承;

【C/C++】【类和对象】多重继承和虚继承

标签:std   其他   不能   通过   定义   value   类构造   成员   移动   

原文地址:https://www.cnblogs.com/Trevo/p/13363941.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!