深度揭秘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++11 并发指南之std::thread 详解

    C++11 并发指南之std::thread 详解

    这篇文章主要介绍了C++11 并发指南之std::thread 详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • C++17文件系统库之std::filesystem 示例详解

    C++17文件系统库之std::filesystem 示例详解

    std::filesystem是C++17引入的一个强大且易用的文件系统操作库,它提供了跨平台的文件系统操作接口,简化了文件和目录操作的代码实现,本文给大家介绍C++17文件系统库之std::filesystem 示例详解,感兴趣的朋友一起看看吧
    2025-03-03
  • C++实现LeetCode(60.序列排序)

    C++实现LeetCode(60.序列排序)

    这篇文章主要介绍了C++实现LeetCode(60.序列排序),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++关于引用(reference)的代码案例

    C++关于引用(reference)的代码案例

    引用是C++中的一种重要特性,它可以让代码更加高效、简洁和易读,本文将深入探讨引用的相关知识,包括引用的概念、使用方法、优点和注意事项等。建议根据给出的代码案例练一下,熟悉即可
    2023-05-05
  • C++实现十进制数转换为二进制数的数学算法

    C++实现十进制数转换为二进制数的数学算法

    这篇文章和大家分享一下我个人对十进制数转换为二进制数的想法,目前暂时更新只整数十进制的转换,后续会更新带有小数的进制转换,代码使用c++实现
    2021-09-09
  • C++使用jsoncpp库解析Json

    C++使用jsoncpp库解析Json

    对json的解析操作是我们日常开发中经常会遇到的一个需求,下面这篇文章主要给大家介绍了关于C++使用jsoncpp库解析Json的相关资料,需要的朋友可以参考下
    2021-06-06
  • C语言详解格式控制符scanf与printf的输入输出

    C语言详解格式控制符scanf与printf的输入输出

    这篇文章主要介绍了C语言格式控制符中输入scanf()和输出printf()的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2022-04-04
  • C++全排列中递归交换法实例详解

    C++全排列中递归交换法实例详解

    在本篇文章里小编给各位整理的是关于C++全排列中递归交换法实例内容,有兴趣的朋友们可以学习下。
    2020-02-02
  • C++无痛实现日期类的示例代码

    C++无痛实现日期类的示例代码

    凡是要写类必须要提到六大默认成员(六位大爷):构造函数、析构函数、拷贝构造函数、赋值重载函数、取地址重载函数(包括const对象和普通对象);那么这次的日期类又需要伺候哪几位大爷呢?本文就来详细说说
    2022-10-10
  • C语言模拟实现密码输入的示例代码

    C语言模拟实现密码输入的示例代码

    本文主要介绍了C语言模拟实现密码输入的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02

最新评论