继承、继承方式
代码复用的方法:组合 (has a);继承 (is a)
继承是提高代码复用性
继承规则:
#include<iostream>
using namespace std;
class A
{
public:int a_num1=1;static void afun(){cout<<"A func"<<endl;}
protected:int a_num2=2;
private:int a_num3=3;
};
//class B: public A
//class B: protected A
class B: private A
{
public:void print(){afun();cout<<a_num1<<endl;cout<<a_num2<<endl;cout<<a_num3<<endl;//不行}int a_num4=4;
};
int main()
{B b;b.print();cout<<b.a_num1<<endl;cout<<b.a_num2<<endl;//不行cout<<b.a_num3<<endl;//不行#if 0cout<<b.a_num1<<endl;b.a_num1=100;cout<<b.a_num1<<endl;cout<<sizeof(B)<<endl;#endifreturn 0;
}
可以参考该博主的链接:C++ 继承 | 菜鸟教程 (runoob.com)
二义性问题
-
在继承时,基类之间、或基类与派生类之间发生成员同名时,将出现对成员访问的不确定性——同名二义性。
-
当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生另一种不确定性——路径二义性。
例子:
一、同名二义性
基类B1和基类B2都存在一样的成员函数Say,派生类C同时继承了B1和B2,这时候如果C的对象使用Say的时候就无法确定该调用哪个基类的Say了。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
二、路径二义性
存在一个祖宗类P,P有成员函数Say。两个基类B1和B2都继承自P,派生类C同时继承了B1和B2。这时候如果C的对象访问Say的时候就无法确定是调用B1的基类P还是B2的基类P。
1 2 3 4 5 6 7 8 9 10 11 |
|
C++继承后的构造函数执行顺序
基类中如果没有无参的构造函数(定义了有参的构造函数,而无无参的),那么,派生类中的每个构造函数,后面都要定义并初始化一个基类的实例化对象:如下
#include <iostream>
using namespace std;
class Test
{
public:Test(){cout<<"Test"<<endl;}
};
class A
{
public:// A()// {// cout << "A" << endl;// }explicit A(int num) : m_num(num){cout << "A int" << endl;}int m_num;~A(){cout << "~A" << endl;}
};class B : public A
{
public:B() :A(5) //m——num(5)这样不行,因为{ //需要基类的定义,初始化,如果基类没有cout << "B" << endl;}B(int count) : m_count(count),A(5)//m_num(5)这样不行;{cout << "B int" << endl;}int m_count;~B(){cout << "~B" << endl;}
};
int main()
{B b;// B b1(5);// B b2=5;// B b3(b);// B b4=b1;return 0;
}
调用顺序:
先调用基类的构造函数(多个基类,根据基类声明的顺序),后调子对象的构造函数(多个子对象的话,根据派生类内的定义顺序先后),最后调派生类的构造函数;
先析构派生类,再析构子对象,最后是析构基类的构造函数:
#include <iostream>
using namespace std;
class Test1
{
public:Test1(){cout << "Test1" << endl;}int t1;~Test1(){cout << "~Test1" << endl;}
};
class Test2
{
public:Test2(){cout << "Test2" << endl;}int t2;~Test2(){cout << "~Test2" << endl;}
};
class C
{
public:C(){cout << "C int" << endl;}explicit C(int num) : m_num(num){cout << "C int" << endl;}int m_num;~C(){cout << "~C" << endl;}
};
class A
{
public:// A()// {// cout << "A int" << endl;// }explicit A(int num) : m_num(num){cout << "A int" << endl;}int m_num;~A(){cout << "~A" << endl;}
};class B : public A, public C // 多个继承写法,以及调用构造函数顺序
{
public:B() : A(5) // m——num(5)这样不行,因为{ // 需要基类的定义,初始化,如果基类没有cout << "B" << endl;}B(int count) : m_count(count), A(5) // m_num(5)这样不行;{cout << "B int" << endl;}int m_count;~B(){cout << "~B" << endl;}Test1 t1_1;Test2 t2_2;
};
int main()
{B b;// B b1(5);// B b2=5;// B b3(b);// B b4=b1;return 0;
}
运行结果:
成员(函数)遮蔽——重载
//基类和派生类内有同名同参函数,调用可以加上作用于限定符;成员(属性)一样可以b.print(); b.A::print();