【C++】面向对象编程的三大特性:深入解析继承机制(一)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【C++】面向对象编程的三大特性:深入解析继承机制

一、前文

面向对象编程的三大特性:封装、继承和多态。

  1. 封装通过将数据和方法封装在对象中,提高了数据的安全性和代码的可维护性。
  2. 继承允许新类从现有类继承属性和方法,实现代码复用和扩展。
  3. 多态则通过统一的接口实现不同的行为,提高了代码的灵活性和扩展性。

封装:

  1. 数据和方法放到一起,把想给访问定义成公有,不想给你访问定义成私有和保护
  2. 一个类型放到另一个类型里面,通过typedef成员函数调整,封装另一个全新的类型相当于武器库

二、继承

2.1 继承概念

  • 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。
  • 它允许一个类(称为子类或派生类)从另一个类(称为父类或基类)继承属性和方法
  • 每个派生类对象都是一个特殊的基类对象,派生类在基类的基础上进行扩展,增加新功能
  • 继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
  • 以前我们接触的复用都是函数复用,继承是类设计层次的复用
using namespace std;
class Person
{
    public:
    void Print()
    {
        cout << "name:" << _name << endl;
        cout << "age:" << _age << endl;
    }
    private:
    string _name = "peter";//名字
    int _age = 18;//年龄
};
class Student : public Person
{
    protected:
    int _stuid;//学号
};
class Teacher : public Person
{
    protected:
    int jobid;//工号
};
int main()
{
    Student s;
    Teacher t;
    s.Print();
    t.Print();
    return 0;
}

从代码中可以看出Person是父类或基类,Student是子类或派生类

2.2 继承关系和访问限定符

2.3 继承基类成员访问方式间变化

注意】:圈出来的是实践中最常见的设计方式,主要了解这部分。

2.4 基类的private成员

基类private成员在派生类中无论以什么方式继承都是不可见的,这里的不可见是指基类的私有成员还是被继承到了派生类中,但是语法上限制派生类对象不管在类里面还是在类外面都是不能去访问

class Person
{
    public:
    void Print()
    {
        cout << "name:" << _name << endl;
        cout << "age:" << _age << endl;
    }
    protected:
    string _name = "peter";
    private:
    int _age = 18;
};
class Student : public Person
{
    public:
    void func()
    {
        cout << _name << endl;
        cout << _age << endl;
    }
    protected:
    int _stuid;
};

按照上面的意思,Student继承了Person属性和方法,但是由于_age是属于私有成员是不可见且不能被访问。

2.4.1 公共接口间接使用基类的私有变量

class Student : public Person
{
    public:
    void func()
    {
        //间接的使用
        Print();
    }
    protected:
    int _stuid;
};

由于基类private成员在派生类中式不能被访问的,如果基类成员不想在类外直接被访问,但是需要在派生类中能访问。这样子可以将基类private成员定义为protected成员,可以看出来保护成员限定符是因继承才出现的

思考:

  • 类可以使用关键字class或者struct,他们只是默认的继承方式不同,为什么不使用struct呢?

解释:

  • struct默认继承方式和访问限定符都是公有的
  • class默认继承方式和访问限定符都是私有的
  • 最好函数显式写出继承方式,偷偷摸摸的不好!

2.5小结

  • 基类的私有成员在子类都是不可见。基类的其他成员在访问方式(取最小的权限)== Min(成员在基类的访问限定符、继承方式)public > prrotected > private
  • 在实际中一般常用的是public继承,而不是protected/private继承,也不提倡使用protected/private继承,因为protected/private继承下来的成员都是只能在派生类的类里面使用,实际中扩展维护性不强

2.6 基类和派生类对象赋值转换

2.6.1 派生类赋值基类

每个派生类对象都是一个特殊的基类对象,派生类在基类的基础上进行扩展,增加新功能

class Person
{
    protected:
    string _name;
    string _sex;
    int _age;
};
class Student : public Person
{
    public:
    int _No; //学号
};

派生类对象可以赋值基类的对象/基类的指针/基类的引用。这里有个形象的说法叫切片或者切割。(将派生类中父类那部分切来赋值过去)。

int main()
{
    Student sobj;
  //子类对象可以赋值给父类对象
    Person pobj = sobj;
    //子类对象可以赋值给父类指针
    Person* pp = &sobj;
    //子类对象可以赋值给父类引用
    Person& rp = sobj;
}

2.6.2 基类对象不能赋值给派生类对象(建立在public继承)

int main()
{
    Student sobj;
    Person pobj = sobj;
    Person* pp = &sobj;
    sobj = pobj;
}

基类是不能直接赋值给派生类,因为可能派生类包含了基类没有的额外属性和方式,而且基类是不具备这些属性和方式,对此不能直接赋值。

2.6.3 强制基类赋值派生类

基类的指针或者引用可用通过强制类型转化赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的。

int main()
{
    Student sobj;
    Person pobj = sobj;
    Person* pp = &sobj;
    1.0
    //pp存放这子类实例的地址,再进行强转
    pp = &sobj; 
    // 这种情况转换时可以的。
    Student* ps1 = (Student*)pp; 
    ps1->_No = 10;
  
    2.0
    //pp存放父类实例的地址
    pp = &pobj;
    // 这种情况转换时虽然可以,但是会存在越界访问的问题
    Student* ps2 = (Student*)pp; 
    ps2->_No = 10;
}

注意:

  • 以上提前需要满足是公有继承
  • 切割/切片是赋值兼容,编译器进行特殊处理,不产生临时对象,将子拷贝给父。内置类型值拷贝,自定义类型调用拷贝构造。


【C++】面向对象编程的三大特性:深入解析继承机制(二)https://developer.aliyun.com/article/1617389

相关文章
|
29天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
38 3
|
1月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
1月前
|
缓存 JavaScript 前端开发
Vue3与Vue2生命周期对比:新特性解析与差异探讨
Vue3与Vue2生命周期对比:新特性解析与差异探讨
89 2
|
12天前
|
编译器 C# 开发者
C# 9.0 新特性解析
C# 9.0 是微软在2020年11月随.NET 5.0发布的重大更新,带来了一系列新特性和改进,如记录类型、初始化器增强、顶级语句、模式匹配增强、目标类型的新表达式、属性模式和空值处理操作符等,旨在提升开发效率和代码可读性。本文将详细介绍这些新特性,并提供代码示例和常见问题解答。
28 7
C# 9.0 新特性解析
|
1月前
|
编译器 程序员 定位技术
C++ 20新特性之Concepts
在C++ 20之前,我们在编写泛型代码时,模板参数的约束往往通过复杂的SFINAE(Substitution Failure Is Not An Error)策略或繁琐的Traits类来实现。这不仅难以阅读,也非常容易出错,导致很多程序员在提及泛型编程时,总是心有余悸、脊背发凉。 在没有引入Concepts之前,我们只能依靠经验和技巧来解读编译器给出的错误信息,很容易陷入“类型迷路”。这就好比在没有GPS导航的年代,我们依靠复杂的地图和模糊的方向指示去一个陌生的地点,很容易迷路。而Concepts的引入,就像是给C++的模板系统安装了一个GPS导航仪
104 59
|
17天前
|
自然语言处理 编译器 Linux
|
11天前
|
C# 开发者
C# 10.0 新特性解析
C# 10.0 在性能、可读性和开发效率方面进行了多项增强。本文介绍了文件范围的命名空间、记录结构体、只读结构体、局部函数的递归优化、改进的模式匹配和 lambda 表达式等新特性,并通过代码示例帮助理解这些特性。
23 2
|
13天前
|
PHP 开发者
PHP 7新特性深度解析及其最佳实践
【10月更文挑战第31天】本文将深入探讨PHP 7带来的革新,从性能提升到语法改进,再到错误处理机制的变革。我们将通过实际代码示例,展示如何高效利用这些新特性来编写更加健壮和高效的PHP应用。无论你是PHP新手还是资深开发者,这篇文章都将为你打开一扇窗,让你看到PHP 7的强大之处。
|
14天前
|
安全 编译器 PHP
PHP 8新特性解析与实践应用####
————探索PHP 8的创新功能及其在现代Web开发中的实际应用
|
16天前
|
Kubernetes Cloud Native 调度
云原生批量任务编排引擎Argo Workflows发布3.6,一文解析关键新特性
Argo Workflows是CNCF毕业项目,最受欢迎的云原生工作流引擎,专为Kubernetes上编排批量任务而设计,本文主要对最新发布的Argo Workflows 3.6版本的关键新特性做一个深入的解析。

推荐镜像

更多