【C++基础】类和对象——继承
继承是面向对象三大特性之一
- 继承可以有效减少重复代码。
- 派生类会继承基类的属性
- 基类表现共性,派生类表现个性
一、继承的基本语法
语法:class 派生类 : 权限 基类 { }
示例:
#include<iostream>
using namespace std;
//父类或称基类
class BasePage
{
public:
void header()
{
cout << "首页、登录、注册(公共头部)" << endl;
}
void footer()
{
cout << "帮助中心、交流合作(公共底部)" << endl;
}
};
//子类或称派生类
class Java : public BasePage
{
public:
void context()
{
cout << "JAVA 页面" << endl;
}
};
//子类或称派生类
class Cpp : public BasePage
{
public:
void context()
{
cout << "Python 页面" << endl;
}
};
int main()
{
Java j;
j.header();
j.context();
j.footer();
cout << endl;
Cpp c;
c.header();
c.context();
c.footer();
}
输出:
二、继承方式
继承语法:class 派生类 : 权限 基类 { }
继承方式一共有三种:
- 公共继承
- 保护继承
- 私有继承
继承规则:
- 私有属性(private):能继承,但会被隐藏,外在表现为未继承。
- 公共权限(public):除了私有权限的属性,其他属性原封不动的继承
- 保护权限(protected):除了私有权限的属性,其他属性均继承为保护权限(保护权限会覆盖公共权限)
继承规则示例:
//基类
class A
{
public:
int a;
protected:
int b;
private:
int c;
};
//派生类
class B : public A
{
//继承来自A的属性
protected:
int a;
int b;
};
//派生类
class C : protected A
{
//继承来自A的属性
protected:
int a;
int b;
};
//派生类
class D : private A
{
//继承来自A的属性
private:
int a;
int b;
};
示例
#include<iostream>
using namespace std;
//基类
class A
{
public:
int a;
protected:
int b;
private:
int c;
};
//派生类
class B : public A
{
public:
void function()
{
a;
b;
}
};
//派生类
class C : protected A
{
void function()
{
a;
b;
}
};
//派生类
class D : private A
{
void function()
{
a;
b;
}
};
int main()
{
//能访问到的属性如下
B b;
b.a; //a为公共权限(public)
C c;
D d;
}
三、继承中的对象模型
派生类继承了基类哪些属性?
利用开发人员命令提示工具查看对象模型
打开vs的开发人员命令提示符
跳转文件路径cd 项目文件夹下
查看命令cl /dl reportSingleClassLayout类名 文件名
示例:
#include<iostream>
using namespace std;
//基类
class Base
{
public:
int b_A;
protected:
int b_B;
private:
int b_C; //被继承了,但也被隐藏了起来
};
//派生类
class Son : Base
{
public:
int s_D;
};
class A
{
public:
int a;
};
int main()
{
//父类中的所有非静态成员属性都会被子类继承下去
//父类中私有成员属性,是被编译器隐藏了,因此访问不到
cout << "sizeof(Son) = " << sizeof(Son) << endl;
cout << "sizeof(A) = " << sizeof(A) << endl;
}
继承中的构造和析构顺序
子类继承父类后,当创建子类对象时,也会调用父类的构造函数
递归调用
- 基类先调用,最后释放
- 派生类后调用,先释放
如图所示
示例:
#include<iostream>
using namespace std;
//基类
class Base
{
public:
Base()
{
cout << "基类的 构造 函数" << endl;
}
~Base()
{
cout << "基类的 析构 函数" << endl;
}
};
//派生类
class Son : Base
{
public:
Son()
{
cout << "派生类的 构造 函数" << endl;
}
~Son()
{
cout << "派生类的 析构 函数" << endl;
}
};
int main()
{
Son s;
}
五、继承同名成员处理方式
基类与派生类出现同名成员时的梳理方式
- 访问派生类同名成员 直接访问即可
- 访问基类同名成员 需要加作用域
示例:
#include<iostream>
using namespace std;
//基类
class Base
{
public:
int a;
void func()
{
cout << "Base 的 func()" << endl;
}
};
//派生类
class Son :public Base
{
public:
void func()
{
cout << "Son 的 func()" << endl;
}
};
int main()
{
Son s;
s.func();
//加基类作用域
s.Base::func();
}
输出:
六、继承同名静态成员处理方式
静态成员和非静态成员出现同名,处理方式一致
- 访问派生类同名成员 直接访问即可
- 访问基类同名成员 需要加作用域
示例:
#include<iostream>
using namespace std;
//基类
class Base
{
public:
int a;
static void func()
{
cout << "Base 的 static func()" << endl;
}
};
//派生类
class Son :public Base
{
public:
static void func()
{
cout << "Son 的 static func()" << endl;
}
};
int main()
{
Son s;
cout << "1、通过对象访问" << endl;
s.func();
s.Base::func();
cout << "2、通过类名访问" << endl;
Son::func();
Base::func();
//访问Son类中继承的基类成员
Son::Base::func();
}
输出:
七、多继承语法
C++允许一个类继承多个类
语法:class 派生类 : 权限 基类1, 权限 基类2 ... { }
出现同名函数,使用作用域来区分
不建议使用多继承
示例:
#include<iostream>
using namespace std;
//基类1
class Base1
{
public:
void func()
{
cout << "Base1 的 func()" << endl;
}
};
//基类2
class Base2
{
public:
void func()
{
cout << "Base2 的 func()" << endl;
}
};
//派生类
class Son :public Base1, public Base2
{
public:
void func()
{
cout << "Son 的 func()" << endl;
}
};
int main()
{
Son s;
s.func();
s.Base1::func();
s.Base2::func();
}
输出:
八、菱形继承
菱形继承概念
- 两个派生类继承同一个基类
- 又有某个类同时继承这两个派生类
- 这种继承被称为菱形继承,或者钻石继承
例如:
菱形继承的问题
- 马和驴都继承了动物的数据,当骡子使用数据时,会产生二义性
- 骡子实际上继承两份相同动物的属性,产生冗余。
问题示例:
#include<iostream>
using namespace std;
class Animal
{
public:
int price;
};
class Horse:public Animal{};
class Donkey :public Animal {};
class Mule :public Horse, public Donkey {};
int main()
{
Mule mule;
mule.Horse::price = 10;
mule.Donkey::price = 20;
//菱形继承时,两个父类拥有相同数据,需要加作用域来区分
cout << "mule.Horse::price = " << mule.Horse::price << endl;
cout << "mule.Donkey::price = " << mule.Donkey::price << endl;
//Mule的price属性只需要一个
}
输出:
使用虚继承来解决菱形继承的问题
示例:
#include<iostream>
using namespace std;
class Animal
{
public:
int price;
};
//使用虚继承来解决菱形继承的问题
//继承之前,加上关键字 virtual 变为虚继承
//此时Animal类称为 虚继承
class Horse:virtual public Animal{};
class Donkey :virtual public Animal {};
class Mule :public Horse, public Donkey {};
int main()
{
Mule mule;
mule.price = 10;
cout << "mule.price = " << mule.price << endl;
cout << "sizeof(mule) = " << sizeof(mule) << endl;
}
输出: