目录

C++ 继承的基本概念

继承类型对比表

继承类模板

继承中的作⽤域

基类和派⽣类间的转换

派生类默认成员函数

继承与友元

多继承及其菱形继承问题

C++多继承及其菱形继承问题解析(无代码)

多继承核心概念

菱形继承问题

解决方案:虚继承

IO库中应用

继承和组合


C++ 继承的基本概念

继承是面向对象编程(OOP)的核心特性之一,允许一个类(派生类也可以叫子类)基于另一个类(基类也可以是父类)构建,继承其成员变量和成员函数。C++ 支持多种继承方式,包括单继承、多继承和虚继承。

继承类型对比表

继承类型 基类 public 成员在派生类中的访问权限 基类 protected 成员在派生类中的访问权限 基类 private 成员在派生类中的访问权限
公有继承 public protected 不可直接访问
保护继承 protected protected 不可直接访问
私有继承 private private 不可直接访问

这个表可以不用记以最小权限为访问权限: public > protected > private ,其中class的继承可以不写private,class默认就是private,则struct默认就是public。如果是private派生类无法访问基类,

protected派生类可以访问但是类外访问不了,public就都可以访问。

class person
{
public:
	person(const std::string& name1,const std::string& ID,const std::string& add )
		:name(name1),
		ID_card(ID),
		address(add)
	{

	}
protected:
	std::string name;
	std::string ID_card;
	std::string address;
};
class my_form :public person 
{
public:
	my_form(const std::string& name1, const std::string& ID, const std::string& add, const std::string& work1)
		:person(name1,ID,add),
		work(work1)
	{

	}
	void Date()
	{
		std::cout <<"名字:" << name << std::endl;
		std::cout << "身份证:" << ID_card << std::endl;
		std::cout << "地址:" << address << std::endl;
		std::cout << "工作:" << work << std::endl;
	}
private:
	std::string work;
};
int main()
{
	my_form i("张三", "12345", "广东", "学生");
	i.Date();
	return 0;
}

继承类模板

类模板和继承——这种继承耦合性高,没有组合好,我们可以创建可以操作多种数据类型的基类,并通过继承机制扩展这些类的功能。这在实现通用数据结构(如链表、树等)或编写与类型无关的算法时特别有用。

#include<vector>
template<class T>
class stack :protected std::vector<T>// stack和vector的关系,既符合is-a,也符合has-a
{
public:
	void push(const T& x)
	{
		std::vector<T>::push_back(x);
	}
	void pop()
	{
		std::vector<T>::pop_back();
	}
	T top()
	{
		return *(std::vector<T>::end()-1);
	}
	size_t size()
	{
		return std::vector<T>::size();
	}
	bool empty()
	{
		return std::vector<T>:: empty();
	}
};

继承中的作⽤域

隐藏规则:

1. 在继承体系中基类和派⽣类都有独⽴的作⽤域。

2. 派⽣类和基类中有同名成员,派⽣类成员将屏蔽基类对同名成员的直接访问,这种情况叫隐藏。 (在派⽣类成员函数中,可以使⽤基类::基类成员显⽰访问)

3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。

4. 注意在实际中在继承体系⾥⾯最好不要定义同名的成员。

class A
{
public:
  void f() { std::cout << "A::f()" << std::endl; }
  int a; 
};
class B : public A
{
public:
	void f(int a) { std::cout << "B::f()" << std::endl; }
	int a;
};
int main()
{
	B b;
	b.f(1);
	b.A::f();

    //b.f()这样子会编译报错
	return 0;
}

基类和派⽣类间的转换

基类和派生类之间的转换主要有三种方式:指针转换、引用转换和对象拷贝。指针和引用转换是隐式的,并且只能访问派生类对象中的基类部分成员;对象拷贝会进行切片操作,只保留派生类对象中的基类部分成员。这些转换在多态性和继承机制中起着重要作用,但也需要注意切片可能带来的信息丢失问题。

派生类默认成员函数

这里的构造跟普通构造差不多,如果没有写构造就是编辑器默认构造,如果自己写了构造编辑器不生成构造,如果加了default就会产生默认构造,其中初始化列表也是一样的。

继承的基类(父类)必须要在自己类里面写默认构造,在子类写会报错,调用默认构造可以看上面代码。

继承与友元

基类友元无法访问派生类对象(还比于父亲的朋友不一定是我朋友),所以继承不了友元

class B;
class A
{
public:
	friend void Print__AB(const A& a,const B& b);
protected:
	int _a;
};
class B : public A
{
protected:
	int _b;
};
void Print__AB(const A &a,const B& b)
{
	std::cout << a._a << b._b << std::cout;//这里会编译器报错访问不了_b.
}

 继承与静态成员

基类定义了static静态成员,则整个继承体系⾥⾯只有⼀个这样的成员。⽆论派⽣出多少个派⽣类,都 只有⼀个static成员实例。

class A
{
public:
	void _apush1()
	{
		_a++;
	}
protected:
	static int _a;
};
int A::_a = 0;
class B : public A
{
public:
	int a_size()
	{
		return _a;
	}
protected:
	int _b;
};
int main()
{
	A y;
	B x; 
	y._apush1();
	x._apush1();
	std::cout<<x.a_size()<<std::endl;//输出2
	return 0;
}

多继承及其菱形继承问题

C++多继承及其菱形继承问题解析(无代码)

多继承核心概念

多继承是面向对象编程中的一种机制,允许一个派生类同时从多个基类继承属性和行为:

  • 基本模型:派生类如同"组装体",整合多个基类的功能
  • 内存布局:派生类对象包含所有基类的子对象(按继承顺序排列)
  • 典型场景:设备控制器(继承输入接口+输出接口+电源管理)
菱形继承问题

当继承结构形成菱形时,引发经典问题:

核心矛盾:

  1. 数据冗余问题

    • B和C各自包含A的完整副本
    • D同时继承B和C → 包含两份A的副本
    • 结果:相同数据重复存储,浪费内存
  2. 访问二义性问题

    • 当D访问A的成员时:
      • 编译器无法确定应通过B路径还是C路径访问
      • 结果:编译错误(ambiguous access)
解决方案:虚继承

通过virtual关键字重构继承关系:

class B : virtual public A {...};
class C : virtual public A {...};
class D : public B, public C {...};

虚继承的魔法:

  1. 共享基类机制

    • B和C不再包含完整A副本
    • 改为存储指向共享A的指针(虚基表指针)
  2. 派生类主导构造

    • 最底层派生类(D)直接构造虚基类(A)
    • 中间类(B/C)不触发A的构造
  3. 访问统一化

    • 所有路径指向同一A实例
    • 彻底消除二义性
IO库中应用

继承和组合

特性 继承(Inheritance) 组合(Composition)
关系语义 "是一个"(is-a) "有一个"(has-a)
耦合度 紧耦合(父子绑定) 松耦合(部件独立)
生命周期 同生共死 自主控制
访问权限 直接访问基类protected成员 仅通过接口访问
典型类比 家族血脉传承 汽车组装零件

                                   ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​  注意尽量使用组合(低耦合关联性低)比较好

更多推荐