深度揭秘C++面向对象编程中继承的核心概念

 更新时间:2023年07月31日 14:16:21   作者:Aomnitrix  
我们知道C语言是面向过程的编程语言,C++在C语言的基础上进化出了面向对象的模型,而继承就是面向对象的重要属性,下面就让小编来和大家详细讲讲吧

一.继承

1.继承与面向对象

我们知道C语言是面向过程的编程语言,C++在C语言的基础上进化出了面向对象的模型。而继承就是面向对象的重要属性。继承使得我们在一个基础属性上能够加以拓展,用来描述很多具有相同基本属性又各有不同的事务。

2.继承方式访问权限

继承方式与访问权限相同都有三种:public、private、protected继承,再结合基类的三种访问权限,在派生类中就有九种不同的情况,可以总结为:基类为私有的成员在派生类一律不可见,其余权限按照与继承方式相比较小的来。

3.切片(赋值转换)

在实际应用场景中我们常用基类代表几种事务共同的基本属性,派生类用来代表自己独特的属性,这就会导致派生类对象一定是包含父类对象的,所以子类对象可以赋给父类对象/指针/引用,过程会将子类中独特属性的成员切出,剩余赋给父类对象,所以称为切片,不仅如此基类的指针可以通过强制类型转换赋值给派生类的指针,代码演示如下:

class Person
{
protected:
	string _name; 
	string _sex;
	int _age; 
};
class Student : public Person
{
public:
	int _No;
};
void Test()
{
	Student sobj;
	// 子类对象可以赋值给父类对象/指针/引用
	Person pobj = sobj;
	Person* pp = &sobj;
	Person& rp = sobj;
	// 基类的指针可以通过强制类型转换赋值给派生类的指针
	pp = &sobj;
	Student * ps1 = (Student*)pp; // 这种情况转换时可以的。
	ps1->_No = 10;
	pp = &pobj;
	Student* ps2 = (Student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问
	ps2->_No = 10;
}
int main()
{
	Test();
	return 0;
}

4.作用域

如果在基类和派生类定义了同名函数就会构成隐藏/重定义,子类成员将屏蔽父类对同名成员的直接访问,如下所示;

class A
{
public:
	A(int num = 0)
	:_num(num)
	{}
	void func()
	{
		cout << _num << endl;
	}
private:
	int _num;
};
class B : public A
{
public:
	B(int val = 1)
		:_val(val)
	{}
	void func()
	{
		cout << _val<< endl;
	}
private:
	int _val;
};
int main()
{
	B b;
	b.func();
	b.A::func();
	return 0;
}

5.默认成员函数

继承这里遵循着一个规则:构造先父后子,析构先子后父。因为派生类中一定包含基类的对象所以派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员,如果基类没有默认的构造函数(无参、全缺省、编译器默认生成),则必须在派生类构造函数的初始化列表阶段显示调用。

派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。

派生类的operator=必须要调用基类的operator=完成基类的复制。

基类的析构函数调用后会自动调用基类的析构函数,不能在派生类显示调用不然无法保证析构先子后父的顺序。

6.友元与静态函数

友元关系不会继承,静态函数不会多次实例化。

7.解决菱形继承的二义性与数据冗余

菱形继承是多继承的一种特殊情况,我们在编写代码时应要避免菱形继承:

如上图所示就是一个菱形继承,这样会导致A类中会有两份P类中的成员,这样不仅会浪费空间,而且会产生二义性,如果我通过A对象访问P中的成员,因为A类中有两份P中的成员所有会有歧义。为了解决此问题,出现了虚拟继承。如下图所示:

那虚继承是如何完成的呢:在d类中建立虚基表,将原来冗余的对象放在d对象空间最下面,B、C原来存储A的位置存储当前位置与空间最下面A对象的偏移量,保证指定B或者C对象访问_a时都能访问到。

8.继承与组合

与继承相比组合的耦合度更低,更适合我们使用!继承又称为白箱复用,组合称为黑盒复用,因为使用组合的话是无法看到类内部的设计。

到此这篇关于深度揭秘C++面向对象编程中继承的核心概念的文章就介绍到这了,更多相关C++继承内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言 操作符#与##使用方法详解

    C语言 操作符#与##使用方法详解

    在类函数宏中(带参数的宏),#号作为一个预处理运算符,可以把记号转换成字符串。##相当于连接符,它会将两边的内容连接起来,形成新的标识符,下面请看详细的教程
    2022-04-04
  • C语言实现数组的循环移位的方法示例

    C语言实现数组的循环移位的方法示例

    这篇文章主要介绍了C语言实现数组的循环移位的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • C++ cmake实现日志类的示例代码

    C++ cmake实现日志类的示例代码

    CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。本文就来利用cmake实现日志类,感兴趣的小伙伴可以了解一下
    2023-03-03
  • windows下vscode使用cmake的方法

    windows下vscode使用cmake的方法

    这篇文章主要介绍了windows下vscode使用cmake的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • C++实现 单例模式实例详解

    C++实现 单例模式实例详解

    这篇文章主要介绍了C++实现 单例模式实例详解的相关资料,需要的朋友可以参考下
    2017-05-05
  • C语言程序如何求学生总成绩和平均成绩

    C语言程序如何求学生总成绩和平均成绩

    这篇文章主要介绍了C语言程序如何求学生总成绩和平均成绩,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • OpenCV使用GrabCut实现抠图功能

    OpenCV使用GrabCut实现抠图功能

    Grabcut是基于图割(graph cut)实现的图像分割算法,它需要用户输入一个bounding box作为分割目标位置,实现对目标与背景的分离/分割。本文将使用GrabCut实现抠图功能,需要的可以参考一下
    2023-02-02
  • C语言中双向链表和双向循环链表详解

    C语言中双向链表和双向循环链表详解

    这篇文章主要介绍了C语言中双向链表和双向循环链表详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • C语言实现24位彩色图像二值化

    C语言实现24位彩色图像二值化

    这篇文章主要为大家详细介绍了C语言实现24位彩色图像二值化,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • C++ std::unique_lock 用法实例详解

    C++ std::unique_lock 用法实例详解

    std::unique_lock 是 C++11 提供的一个用于管理互斥锁的类,它提供了更灵活的锁管理功能,适用于各种多线程场景,这篇文章给大家介绍了C++ std::unique_lock 用法,感兴趣的朋友跟随小编一起看看吧
    2023-09-09

最新评论