继承、继承方式
代码复用的方法:组合 (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 0
cout<<b.a_num1<<endl;
b.a_num1=100;
cout<<b.a_num1<<endl;
cout<<sizeof(B)<<endl;
#endif
return 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();