1.定义
面向对象的三大特征之一,为了减少重复的代码
2.语法
class 子类 :继承方式 父类 (子类也叫派生类,父类也称为基类)
例:class age:public person;
#include<iostream>
using namespace std;
#include<string>
class age;
class base
{
public:
void header()
{
cout << "首页" << endl;
}
void footer()
{
cout << "尾页" << endl;
}
};
class cpp :public base
{
public:
void content()
{
cout << "视频内容" << endl;
}
};
int main()
{
cpp p;
p.header();
p.content();
p.footer();
system("pause");
return 0;
}
3.继承方式
1.分类
公共继承 :原样复制父类中的类型,不可访问private
保护继承:将public变为protected类型,不可访问private
私有继承:将public和privated变为private,不可访问private
2.语法
(需要用函数来访问,并且函数也要有类型)
#include<iostream>
using namespace std;
#include<string>
class age;
class base
{
public:
int a = 10;
protected:
int b = 10;
private:
int c = 10;
};
class cpp :public base
{
public:
void fun()
{
a = 100;
b = 100;
}
};
int main()
{
cpp p;
system("pause");
return 0;
}
注意:子类中不能访问父类中的private类型
错误示例
#include<iostream>
using namespace std;
#include<string>
class age;
class base
{
public:
int a = 10;
protected:
int b = 10;
private:
int c = 10;
};
class cpp :public base
{
public:
void fun()
{
a = 100;
b = 100;
c = 100;
}
};
int main()
{
cpp p;
system("pause");
return 0;
}
4.继承中的对象模型
结论:父类中所有非静态成员都会被继承下去,私有成员属性是被编译器隐藏了,隐刺是访问不到的,但确实是被继承下去了。
#include<iostream>
using namespace std;
#include<string>
class age;
class base
{
public:
int a = 10;
protected:
int b = 10;
private:
int c = 10;
};
class cpp :public base
{
public:
int d = 10;
};
int main()
{
cpp p;
cout << "size:" << sizeof(cpp) << endl;
system("pause");
return 0;
}
注意:可以利用开发人员命令提示符工具查看对象模型。
先进后出
5.构造和析构顺序
先构造父类再构造子类,析构的顺序与构造的顺序相反。
#include<iostream>
using namespace std;
#include<string>
class age;
class base
{
public:
base()
{
cout << "base构造函数" << endl;
}
~base()
{
cout << "base析构函数" << endl;
}
};
class cpp :public base
{
public:
cpp()
{
cout << "cpp构造函数" << endl;
}
~cpp()
{
cout << "cpp析构函数" << endl;
}
};
int main()
{
cpp p;
return 0;
}
6.同名成员处理
当父类中的属性和子类中的属性重合的情况
cout<<"子类下面的成员"<<s.m_a<<endl;
cout<<"父类下面的成员"<<s.base::m_a<<endl;
7.同名函数处理
1.直接调用调用的是子类中的同名成员
(如果子类中出现和父类同名的成员函数,子类中的同名函数会隐藏父类中的所有同名)
s.fun();
2.调用父类中的同名成员
(如果想访问父类中被隐藏的成员函数,需要加作用域)
s.base::fun();
8.同名静态成员访问
1.通过对象访问
cout<<"子类"<<s.m_a<<endl;
cout<<"父类"<<s.base::m_a<<endl;
2.通过类名访问
cout<<"子类"<<son::m_a<<endl;
cout<<"父类"<<base::m_a<<endl;
cout<<"父类"<<son::base::m_a<<endl;
9.同名静态函数访问
子类中如果出现和父类中同名的静态成员函数,会隐藏父类中的静态成员函数。
如果想访问父类中的静态成员函数,需要加作用域。
10.多继承语法
C++允许一个类继承多个类
语法:class 子类:继承方式 父类1,继承方式 父类2。。。
注意
1.不过多继承可能会引发父类中有同名成员出现,需要加作用域来区分,所以C++实际开发中不建议使用多继承。
2.当父类中出现同名成员,需要加作用域来区分
cout<<"1号父类"<<s.base1::m_a<<endl;
cout<<"2号父类"<<s.base2::m_a<<endl;
11.菱形继承问题
带来的影响是他会继承两份age,占用两份资源,造成浪费。
1.图示
2.代码演示
#include<iostream>
using namespace std;
#include<string>
class animal
{
public:
int age = 15;
};
class sheep:public animal
{
public:
int age = 10;
};
class camel:public animal
{
public:
int age = 20;
};
class cnm :public sheep, public camel
{};
int main()
{
animal a;
sheep b;
camel c;
cnm d;
cout << "animal:" << a.age << endl;
cout << "sheep:" << b.age << endl;
cout << "camel:" << c.age << endl;
cout << "animal 2:" << a.age << endl;
cout << "sheep 2:" << b.age << endl;
cout << "camel 2:" << c.age << endl;
cout << "cnm.sheep:" << d.sheep::age << endl;
cout << "cnm.camel:" << d.camel::age << endl;
return 0;
}
注意:当菱形继承时,两个父类拥有相同的数据,需要加以作用域区分。cnm只有一个age就可以,菱形继承导致有两个age,造成数据浪费。
错误示范:
#include<iostream>
using namespace std;
#include<string>
class animal
{
public:
int age = 15;
};
class sheep:public animal
{
};
class camel:public animal
{
};
class cnm :public sheep, public camel
{};
int main()
{
animal a;
sheep b;
camel c;
cnm d;
cout << "cnm:" << d.age << endl;//会报错
return 0;
}
3.解决方法
利用虚继承解决菱形继承问题
1.语法
继承之前,加上关键字virtual变为虚继承。此时的animal称为虚基类。
2.代码演示
#include<iostream>
using namespace std;
#include<string>
class animal
{
public:
int age = 15;
};
class sheep:virtual public animal
{
};
class camel:virtual public animal
{
};
class cnm :public sheep, public camel
{};
int main()
{
animal a;
sheep b;
camel c;
cnm d;
d.sheep::age = 10;
d.camel::age = 20;
cout << "cnm.sheep:" << d.sheep::age << endl;
cout << "cnm.camel:" << d.camel::age << endl;
cout << "cnm:" << d.age << endl;
return 0;
}
在菱形继承的中间两层加上关键字virtual之后,访问a.sheep::age和a.camel::age结果都变为最后更改的值,也可以用 cout << "cnm:" << d.age << endl;进行访问了。(相当于这四个继承够公用一个age)
3.底层原理
virtual关键字其实让继承的由一个变量变为了继承一个指针。