1.基本语法
继承:减少重复代码
语法:class 子类:继承方式 父类
子类也叫派生类,父类也叫基类
派生类中的成员包括两大部分
一类是从基类继承过来的,一类是自己增加的成员。
从基类继承过来的表现其共性,而新增的成员体现了其个性。
#include<iostream>
#include<string>
using namespace std;
class BasePage {//基类
public:
void header() {
cout << "1" << endl;
}
void footer() {
cout << "2" << endl;
}
};
class Java :public BasePage {//派生类
public:
void content() {
cout << "Java学科视频" << endl;
}
};
class Python :public BasePage {
public:
void content() {
cout << "Python学科视频" << endl;
}
};
void test01() {
Java j;
j.header();
j.footer();
j.content();
Python p;
p.content();
p.footer();
p.header();
}
int main() {
test01();
return 0;
}
2.继承方式
父类中私有的内容子类不管是哪种继承方式子类都不能访问,
公共继承:父类的公共和保护在子类中依然是相应的公共和保护,
保护继承:父类中除私有继承之外的在子类中全部变成保护权限
私有继承:父类中的所有内容(除私有的)在子类中全部变成私有权限
3.继承中的对象模型
首先来了解一下派生类里有什么
父类中所有非静态成员属性都会被子类继承下去
父类中的私有属性是被编译器给隐藏了,因此是访问不到,但是确实被继承下去了。
#include<iostream>
#include<string>
using namespace std;
class Base1{
public:
int m_a;
protected:
int m_b;
private:
int m_c;
};
class Son1 :public Base1 {
public:
int m_d;
};
void test01() {
cout << "size of son=" << sizeof(Son1) << endl;
}
int main() {
test01();
return 0;
}
可以利用开发人员命令提示符查看对象模型
先跳转文件所在盘D:
跳转文件路径 cd 粘贴具体路径
查看命名 dir
//cl /d1 reportSingleClassLayout类名 文件名
文件名可以用Tab键补全
4.继承中构造和析构的顺序
子类继承父类后,当创建子类对象,也会调用父类的构造函数
问题: 父类和子类的构造和析构顺序谁先谁后
#include<iostream>
#include<string>
using namespace std;
class Base{
public:
Base() {
cout << "父类的构造函数" << endl;
}
~Base() {
cout << "父类的析构函数" << endl;
}
};
class Son :public Base {
public:
Son() {
cout << "子类的构造函数" << endl;
}
~Son() {
cout << "子类的析构函数" << endl;
}
};
void test01() {
Son s;
}
int main() {
test01();
return 0;
}
5.继承同名成员处理方式
当子类与父类出现同名成员时,如何通过子类对象,访问到子类或父类中同名的数据:
访问子类同名成员,直接访问即可。
访问父类同名成员,需要加作用域。
#include<iostream>
#include<string>
using namespace std;
class Base{
public:
Base() {
m_a = 100;
}
int m_a;
};
class Son :public Base {
public:
Son() {
m_a = 200;
}
int m_a;
};
void test01() {
Son s;
//访问子类同名成员,直接访问即可
cout << s.m_a << endl;
//如果通过子类访问父类的同名成员,需要加一个作用域
cout << s.Base::m_a << endl;
}
int main() {
test01();
return 0;
}
同名成员函数也是这样
如果子类中出现和父类同名的成员函数,子类中的同名成员会隐藏掉父类中所有的同名函数(包括重载的那点(比如多一个形参)),如果想访问到父类中被隐藏的同名函数,加作用域。
6.继承同名静态成员处理方式
继承中同名的静态成员在子类对象上如何进行访问?
静态成员和非静态成员出现同名,处理方式一致。
访问子类同名成员,直接访问
访问父类同名成员,加作用域
#include<iostream>
#include<string>
using namespace std;
class Base{
public:
Base() {
}
static int m_a;
};
int Base::m_a = 100;
class Son :public Base {
public:
Son() {
}
static int m_a;
};
int Son::m_a = 200;
void test01() {
Son s;
//访问子类同名成员,直接访问即可
cout << s.m_a << endl;
//如果通过子类访问父类的同名成员,需要加一个作用域
cout << s.Base::m_a << endl;
}
int main() {
test01();
return 0;
}
注意这个赋值是在类外赋值,没有在构造函数里赋值,如果在构造函数里赋值会报错。
ps:静态成员访问方式有两种
第一种是通过对象来访问
第二种是通过类名来访问
cout << Son::m_a << endl;
//第一个::通过类名方式访问第二个::代表父类作用域下
cout << Son::Base::m_a << endl;
静态同名成员函数和成员变量一样
7.多继承语法
C++允许一个类继承多个类
语法 class 子类:继承方式 父类1,继承方式 父类2…
多继承会引起重名,如果出现了同名的情况,子类使用的时候要加作用域
class Son :public Base1,public Base2
8.菱形继承
典型的菱形继承案例
菱形继承问题:
二义性可以用表明作用域解决
#include<iostream>
#include<string>
using namespace std;
//动物类
class Animal{
//如果不写public,那么成员变量会默认为私有属性
public:
int m_Age;
};
//羊类
class Sheep:virtual public Animal {
public:
};
//驼类
class Tuo :virtual public Animal {
public:
};
class yangtuo:public Sheep,public Tuo{};
void test01() {
yangtuo yt;
yt.Sheep::m_Age=3;
yt.Tuo::m_Age = 5;
}
int main() {
test01();
return 0;
}
年龄这份数据我们知道只有一份就可以,但这个有两个该怎么处理
//利用虚继承解决菱形继承的问题
//继承之前加上关键字 virtual 变为虚继承
//Animal 类称为虚基类
//羊类
class Sheep :virtual public Animal{}
#include<iostream>
#include<string>
using namespace std;
//动物类
class Animal{
//如果不写public,那么成员变量会默认为私有属性
public:
int m_Age;
};
//羊类
class Sheep:virtual public Animal {
public:
};
//驼类
class Tuo :virtual public Animal {
public:
};
class yangtuo:public Sheep,public Tuo{};
void test01() {
yangtuo yt;
yt.Sheep::m_Age=3;
yt.Tuo::m_Age = 5;
cout << yt.m_Age << endl;
//当出现菱形继承的时候,有两个父类具有相同的数据需要加作用域区分
}
int main() {
test01();
return 0;
}
写上了虚基类之后年龄就只有一个了
vbptr 虚基类指针,继承继承的是两个指针