📜  C ++ |继承|问题5(1)

📅  最后修改于: 2023-12-03 15:29:42.656000             🧑  作者: Mango

C++ | 继承 | 问题5

继承是面向对象编程中一个重要的概念,可以让子类继承父类的属性和方法,从而提高代码复用性并简化开发过程。在 C++ 中,继承有多种类型,并且存在一些特殊的情况需要特别注意。

继承的基本概念
派生类的定义

C++ 中使用 classstruct 定义派生类时,通常需要继承一个或多个基类。继承语法如下所示:

class ChildClass : public ParentClass {
    // ...
};

其中,ChildClass 即为派生类,ParentClass 则为基类。派生类可以在基类提供的成员函数和成员变量基础上增加额外的功能。

继承的类型

在 C++ 中,派生类可以通过不同的继承方式继承基类,包括:

  • 公有继承:使用 public 关键字表示,派生类继承了基类的所有公有成员;
  • 保护继承:使用 protected 关键字表示,派生类继承了基类的所有公有和保护成员;
  • 私有继承:使用 private 关键字表示,派生类继承了基类的所有公有、保护和私有成员,但是基类的所有成员在派生类中均变为私有成员。
访问基类成员

在派生类中,可以通过基类名限定符的方式访问基类中的成员。例如,假设 ChildClass 继承自 ParentClass,则可以通过以下方式访问基类中的公有成员 parentMember

class ChildClass : public ParentClass {
public:
    void childMethod() {
        parentMember = 10; // 直接访问基类成员
        ParentClass::parentMember = 20; // 使用限定符访问基类成员
    }
};
继承中的特殊情况
二义性

在多重继承的情况下,如果派生类同时从两个或更多个基类中继承了相同的成员,则可能会导致二义性问题。例如,假设 ChildClass 同时从 ClassAClassB 中继承了一个名为 member 的成员:

class ClassA {
public:
    int member;
};

class ClassB {
public:
    int member;
};

class ChildClass : public ClassA, public ClassB {
public:
    void childMethod() {
        //member = ?; // 二义性问题:无法确定访问哪个基类的成员
    }
};

在这种情况下,访问 member 成员时将会出现二义性问题,需要使用基类名限定符来解决。

菱形继承

菱形继承指的是多重继承中的一种情况,其中有一个类同时继承自两个以上的类,在这些类中又有一个共同的基类,如下图所示:

在这种情况下,派生类将会继承两个相同基类的实例,可能会导致内存浪费和二义性问题。例如,假设 LeafClass 继承自 ParentBParentC,而这两个类又都继承自 ParentA

class ParentA {
public:
    int memberA;
};

class ParentB : public ParentA {
public:
    int memberB;
};

class ParentC : public ParentA {
public:
    int memberC;
};

class LeafClass : public ParentB, public ParentC {
public:
    void leafMethod() {
        ParentB::memberA = 10; // 正确,指定了访问哪个基类的成员
        //memberA = ?; // 二义性问题:无法确定访问哪个基类的成员
    }
};

在这种情况下,访问 memberA 成员时也会出现二义性问题,需要使用基类名限定符来指定访问哪个基类的成员。

虚继承

虚继承是为了解决菱形继承问题而引入的一种继承方式,可以让派生类共享基类的实例。虚继承使用 virtual 关键字表示,派生类继承的是基类的虚基类而不是直接继承自基类。例如,通过将 ParentA 改为虚基类,可以解决上述菱形继承的问题:

class ParentA {
public:
    int memberA;
};

class ParentB : virtual public ParentA {
public:
    int memberB;
};

class ParentC : virtual public ParentA {
public:
    int memberC;
};

class LeafClass : public ParentB, public ParentC {
public:
    void leafMethod() {
        memberA = 10; // 正确:共享基类实例
    }
};

在这种情况下,派生类 LeafClass 将会共享基类 ParentA 的实例,可以避免内存浪费和二义性问题。

总结

继承是 C++ 中一种重要的概念,可以让派生类继承基类的属性和方法,从而提高代码复用性。在使用继承时,需要注意多重继承和菱形继承可能会导致二义性和内存浪费问题,可以通过基类名限定符和虚继承来解决这些问题。