迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > C++ >

C++ 子类继承

作者:迹忆客 最近更新:2023/08/22 浏览次数:

继承是 OOP 的一个特性,其中一个类获取另一个类的属性和行为。 继承另一个类的类称为子类,而其属性被继承的类称为基类。

本文将讨论继承类时出现的钻石问题。


C++ 子类继承

继承是一种让一个类继承另一个类的属性的功能。 继承另一个类的属性的类称为子类或派生类,而继承其属性的类称为基类或父类。

现实世界中继承的一个例子是孩子继承其父母的财产。

C++中的继承主要有五种类型,即单继承、多重继承、多级继承、层次继承和混合继承。

  1. 单一继承 - 在这种类型的继承中,单个子类继承自单个基类。
  2. 多重继承 - 在这种类型的继承中,子类是从多个基类继承的。
  3. 分层继承 - 在这种类型的继承中,多个子类从同一个基类继承。
  4. 多级继承 - 在这种类型的继承中,一个类被另一个类继承,而另一个类又被其他一些类继承。 比如我们有A、B、C三个类,其中C类被B类继承,B类被A类继承。
  5. 混合继承 - 在这种类型的继承中,组合了多种类型的继承。

我们首先讨论C++中的多重继承和层次继承。


C++ 子类的多重继承

如前所述,在多重继承中,子类被多个其他基类继承。 让我们举个例子来详细理解多重继承。

#include<iostream>
using namespace std;
class Base1
{
    public:
        Base1() {
            cout << "Base class 1" << endl;
        }
};

class Base2
{
    public:
        Base2() {
            cout << "Base class 2" << endl;
        }
};

class Derived: public Base2, public Base1
{
    public:
        Derived() {
            cout << "Derived class" << endl;
        }
};

int main()
{
  Derived d;
  return 0;
}

输出:

Base class 2
Base class 1
Derived class

上面的代码有两个基类Base1和Base2,Derived类继承自这两个基类。 但是,您必须注意基类构造函数的调用顺序。

首先,调用 Base2 类构造函数,因为 Derived 类首先继承它,然后调用 Base1 构造函数。


C++中子类的层次继承

如前所述,在层次继承中,多个子类是从单个基类继承的。 我们通过一个例子来详细了解一下层次继承。

#include<iostream>
using namespace std;
class Base
{
    public:
        Base() {
            cout << "Base class" << endl;
        }
};

class Derived1: public Base
{
    public:
        Derived1() {
            cout << "Derived class 1" << endl;
        }
};

class Derived2: public Base
{
    public:
        Derived2() {
            cout << "Derived class 2" << endl;
        }
};

int main()
{
  Derived1 d1;
  Derived2 d2;
  return 0;
}

输出:

Base class
Derived class 1
Base class
Derived class 2

上面的代码示例有三个类,其中 Derived1 和 Derived2 类继承自公共 Base 类。


C++ 继承中的钻石问题

当我们将层次继承和多重继承结合起来时,就会出现钻石问题。 之所以这样称呼这个问题,是因为类在相互继承的同时形成了菱形。

假设我们有一个场景,有四个类 A、B、C 和 D。

A 类充当基类。 B类被A类继承。 C类也被A类继承。 D 类被 B 类和 C 类继承。

继承中的钻石问题

现在让我们通过代码看看出现的问题。

#include<iostream>
using namespace std;
class A
{
    public:
        A() {
            cout << "Constructor A here!" << endl;
        }
};

class B: public A
{
    public:
           B() {
            cout << "Constructor B here!" << endl;
        }
};

class C: public A
{
    public:
    C() {
        cout << "Constructor C here!" << endl;
    }
};

class D: public B, public C
{
    public:
        D(){
            cout<<"Constructor D here!"<< endl;
        }
};

int main()
{
  D d;
  return 0;
}

输出:

Constructor A here!
Constructor B here!
Constructor A here!
Constructor C here!
Constructor D here!

上面的输出显示,类 A 的构造函数被调用了两次,因为类 D 获得了类 A 的两个副本。一个通过继承类 B,另一个通过继承类 C。

这会产生歧义,在 C++ 中称为钻石问题。

这个问题主要发生在一个类继承多个基类时,这些基类继承自一个公共基类。

不过,这个问题可以使用C++中的virtual关键字来解决。 我们让双父类从同一个基类继承为虚拟类,这样子类就不会获得公共祖父母类的两个副本。

因此,我们在代码示例中创建 B 类和 C 类虚拟类。

让我们借助代码示例来了解此问题的解决方案。

#include<iostream>
using namespace std;
class A
{
    public:
        A() {
            cout << "Constructor A here!" << endl;
        }
};

class B: virtual public A
{
    public:
           B() {
            cout << "Constructor B here!" << endl;
        }
};

class C: virtual public A
{
    public:
    C() {
        cout << "Constructor C here!" << endl;
    }
};

class D: public B, public C
{
    public:
        D(){
            cout<<"Constructor D here!"<< endl;
        }
};

int main()
{
  D d;
  return 0;
}

输出:

Constructor A here!
Constructor B here!
Constructor C here!
Constructor D here!

因此,如上面的输出所示,现在我们只获得了类 A 的构造函数的一份副本。 virtual 关键字告诉编译器,类 B 和类 C 都继承自同一个基类 A; 因此,它应该只被调用一次。


总结

在本文中,我们简要讨论了继承和继承的类型。 然而,我们主要详细讨论了两种类型的继承——多重继承和层次继承,这引起了继承中的钻石问题。

当一个类从多个基类继承,而该基类又从单个基类继承时,就会出现菱形问题。 不过这个问题在C++中使用virtual关键字就解决了。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

C++ 调用基类方法

发布时间:2023/08/22 浏览次数:118 分类:C++

本文将讨论使用 C++ 从子类调用父类方法。 首先,我们将快速刷新继承。稍后我们将讨论不同场景下调用基类方法以及相关问题。

检查C++中的链表是否为空

发布时间:2023/08/22 浏览次数:127 分类:C++

链表具有多个动态分配的节点,其中包含一个值和一个指针。 本教程将教您三种在 C++ 中检查链表是否为空的方法。C++ 中使用根元素检查链表是否为空 链表中的根充当一个元素,即使链表为空

C++ 中的移动语义

发布时间:2023/08/22 浏览次数:160 分类:C++

在本文中,我们将讨论 C++ 中的移动语义:我们将讨论深拷贝和浅拷贝的相关概念 我们将快速讨论左值和右值的概念。 我们将尝试通过示例来理解移动语义。

在 C++ 中抛出异常

发布时间:2023/08/21 浏览次数:200 分类:C++

C++抛出异常是C++的一个强大功能,可用于处理错误和意外事件。 它主要用于终止程序的执行或将控制权转移到程序的不同部分。在 C++ 中抛出异常

C++ 中抛出超出范围的异常

发布时间:2023/08/21 浏览次数:176 分类:C++

This article discusses how to throw an out of range exception in C++. It also discusses the possible errors while throwing out of range exception in C++.

在 C++ 中抛出异常消息

发布时间:2023/08/21 浏览次数:192 分类:C++

它是通过在程序中可能出现问题的地方抛出异常来执行的。 C++ 中有几个异常处理关键字,但本文将介绍如何使用可变消息引发异常。使用标准 C++ 异常抛出带有消息的异常 - 无效参数

C++ 中的 A Declaration Shadows a Parameter 错误

发布时间:2023/08/21 浏览次数:188 分类:C++

每个对象或变量总是有一些边界、范围或作用域来访问其他类成员,例如由 C++ 中的访问说明符定义为 public、private 或 protected 的数据成员或成员函数。当我们在程序的特定范围或块中多次定义

C++ 中的错误 Error ID Returned 1 Exit Status

发布时间:2023/08/21 浏览次数:130 分类:C++

C++ [Error]: Id returned 1 exit status 不是常见错误。 这通常意味着程序崩溃了,并且在不查看堆栈跟踪的情况下很难确定原因。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便