C++ 入门10:继承和派生类

往期回顾:

C++ 入门07:静态成员和常量成员-CSDN博客

C++ 入门08:运算符重载-CSDN博客

C++ 入门09:友元函数和友元类-CSDN博客


一、前言

在前面文章的学习中,我们了解了类和对象的基础知识、构造函数、拷贝构造函数、静态成员、常量成员、运算符重载、友元函数和友元类。今天,我们将学习 C++ 中的继承和派生类。继承是面向对象编程中的一个重要概念,它允许我们创建一个新的类,该类继承一个或多个现有类的属性和方法,从而实现代码的重用和扩展。

二、 继承和派生类

2.1、什么是继承?

继承(Inheritance)是面向对象编程(OOP)中一个核心概念,它为代码的复用和组织提供了一种强有力的机制。通过继承,我们可以创建一个新的类(派生类或子类),这个新类继承了另一个已存在类(基类或父类)的属性和行为(即成员变量和方法)。继承使得子类可以复用父类的代码,同时还可以添加新的属性和方法或覆盖(重写)父类中的方法,以满足特定的需求。

继承不仅减少了代码冗余,提高了代码的可维护性,还促进了多态性的实现,使得不同类的对象可以通过统一的接口进行操作。

语法:

在 C++ 中,继承关系是通过在派生类的定义中,使用冒号(:)后跟基类名来指定的。基本语法如下:

class BaseClass {  
    // 基类的成员变量和成员函数  
};  
  
class DerivedClass : public BaseClass {  
    // 派生类的成员变量和成员函数  
    // 这里可以添加新的成员,也可以重写基类的成员函数  
};

在上述示例中,DerivedClass 是通过继承 BaseClass 创建的。

示例:

我们定义一个基类 Person,表示一个人的基本信息,然后定义一个派生类 Student,表示学生的特有信息。

#include <iostream>
using namespace std;

// 基类 Person
class Person {
public:
    string name;
    int age;

    Person(string n, int a) : name(n), age(a) {}

    void displayInfo() {
        cout << "Name: " << name << endl;
        cout << "Age: " << age << endl;
    }
};

// 派生类 Student
class Student : public Person {
public:
    string school;

    Student(string n, int a, string s) : Person(n, a), school(s) {}

    void displayStudentInfo() {
        displayInfo();
        cout << "School: " << school << endl;
    }
};

int main() {
    Student student("John", 20, "XYZ University");
    student.displayStudentInfo();

    return 0;
}

在这个示例中,Student 类继承自 Person 类,因此它具有 Person 类的所有成员变量和成员函数。我们在 Student 类中添加了一个新的成员变量 school 和一个新的成员函数 displayStudentInfo

2.2、 访问控制

在继承中,基类的成员可以根据其访问控制权限决定派生类对它们的访问权限。访问控制有三种:publicprotectedprivate

(1)public 继承

当派生类以 public 方式继承基类时,基类的 public 成员在派生类中保持 public,基类的 protected 成员在派生类中保持 protected,基类的 private 成员在派生类中不可访问。

(2)protected 继承

当派生类以 protected 方式继承基类时,基类的 public 成员和 protected 成员在派生类中都变成 protected,基类的 private 成员在派生类中不可访问。

(3)private 继承

当派生类以 private 方式继承基类时,基类的 public 成员和 protected 成员在派生类中都变成 private,基类的 private 成员在派生类中不可访问。

示例:

我们使用相同的 PersonStudent 类来演示不同的继承方式。

#include <iostream>
using namespace std;

class Person {
public:
    string name;
    int age;

    Person(string n, int a) : name(n), age(a) {}

    void displayInfo() {
        cout << "Name: " << name << endl;
        cout << "Age: " << age << endl;
    }
};

class StudentPublic : public Person {
public:
    string school;

    StudentPublic(string n, int a, string s) : Person(n, a), school(s) {}

    void displayStudentInfo() {
        displayInfo();
        cout << "School: " << school << endl;
    }
};

class StudentProtected : protected Person {
public:
    string school;

    StudentProtected(string n, int a, string s) : Person(n, a), school(s) {}

    void displayStudentInfo() {
        displayInfo();
        cout << "School: " << school << endl;
    }
};

class StudentPrivate : private Person {
public:
    string school;

    StudentPrivate(string n, int a, string s) : Person(n, a), school(s) {}

    void displayStudentInfo() {
        displayInfo();
        cout << "School: " << school << endl;
    }
};

int main() {
    StudentPublic studentPublic("John", 20, "XYZ University");
    studentPublic.displayStudentInfo();
    cout << "Accessing public inherited member: " << studentPublic.name << endl;

    StudentProtected studentProtected("Alice", 21, "ABC University");
    studentProtected.displayStudentInfo();
    // cout << "Accessing protected inherited member: " << studentProtected.name << endl; // 错误

    StudentPrivate studentPrivate("Bob", 22, "DEF University");
    studentPrivate.displayStudentInfo();
    // cout << "Accessing private inherited member: " << studentPrivate.name << endl; // 错误

    return 0;
}

在这个示例中,我们定义了三个派生类 StudentPublicStudentProtectedStudentPrivate,分别使用 publicprotectedprivate 继承方式。可以看到,不同的继承方式会影响派生类对基类成员的访问权限。 

选择哪种继承方式取决于具体的设计需求,但大多数情况下,公有继承是最常用的。

继承还允许我们实现接口继承和实现继承。在接口继承中,我们主要继承基类的接口(即方法签名),而不关心实现细节。而在实现继承中,我们不仅继承了基类的接口,还继承了其实现代码,并可以在派生类中对这些实现进行扩展或修改。

 2.3、 多重继承

(1)什么是多重继承

C++ 支持一个类从多个基类继承,这种特性被称为多重继承(Multiple Inheritance)。多重继承是面向对象编程中一个强大但复杂的概念,它允许派生类同时继承多个基类的属性和方法。这种机制为类的设计提供了更高的灵活性和表达力,但也引入了额外的复杂性和潜在的问题,如命名冲突(也称为菱形继承问题或钻石继承问题)和对象切片等。

语法

在 C++ 中,多重继承的语法与单继承类似,只是在派生类的定义中指定了多个基类。使用逗号(,)分隔多个基类。以下是多重继承的基本语法示例:

class Base1 {  
    // Base1 的成员  
};  
  
class Base2 {  
    // Base2 的成员  
};  
  
class Derived : public Base1, public Base2 {  
    // Derived 继承自 Base1 和 Base2  
    // Derived 可以添加新的成员,也可以重写 Base1 和 Base2 中的成员函数  
};

 在这个例子中,Derived 类同时继承了 Base1 和 Base2 两个基类。它可以使用这两个基类中的所有公有和保护成员(除非在派生类中被重写)。

(2)命名冲突

当多个基类中包含同名的成员时,多重继承会导致命名冲突。为了解决这个问题,C++ 提供了作用域解析运算符(::)来明确指定要访问的成员属于哪个基类。例如:

Derived obj;  
obj.Base1::memberFunction(); // 调用 Base1 中的 memberFunction  
obj.Base2::memberFunction(); // 调用 Base2 中的 memberFunction

(3)菱形继承问题(钻石继承问题)

菱形继承是多重继承中一个常见的问题,它发生在多个基类最终都继承自同一个基类,但路径不同的情况下。这会导致在派生类中存在多个基类的副本,从而浪费内存并可能引发其他问题。为了解决这个问题,C++ 提供了虚基类(Virtual Base Class)的概念。

(4)虚基类

在 C++ 中,可以将基类声明为虚基类,以解决菱形继承问题。当基类被声明为虚基类时,无论它在继承层次结构中出现多少次,派生类中都只会有一个该基类的实例。这通过确保基类在继承树中的唯一性来减少内存浪费,并避免潜在的歧义。

class VirtualBase {  
    // VirtualBase 的成员  
};  
  
class Base1 : virtual VirtualBase {  
    // Base1 继承自 VirtualBase 作为虚基类  
};  
  
class Base2 : virtual VirtualBase {  
    // Base2 也继承自 VirtualBase 作为虚基类  
};  
  
class Derived : public Base1, public Base2 {  
    // Derived 继承自 Base1 和 Base2,它们都继承自 VirtualBase 作为虚基类  
    // 这里只会有一个 VirtualBase 的实例  
};

在这个例子中,Derived 类通过 Base1 和 Base2 间接继承了 VirtualBase,但由于 VirtualBase 被声明为虚基类,Derived 类中只会有一个 VirtualBase 的实例。这解决了菱形继承问题,并确保了基类成员的唯一性和一致性。

示例:

我们定义两个基类 PersonEmployee,然后定义一个派生类 Manager,它继承自 PersonEmployee

#include <iostream>
using namespace std;

class Person {
public:
    string name;
    int age;

    Person(string n, int a) : name(n), age(a) {}

    void displayPersonInfo() {
        cout << "Name: " << name << endl;
        cout << "Age: " << age << endl;
    }
};

class Employee {
public:
    int employeeID;

    Employee(int id) : employeeID(id) {}

    void displayEmployeeInfo() {
        cout << "Employee ID: " << employeeID << endl;
    }
};

class Manager : public Person, public Employee {
public:
    Manager(string n, int a, int id) : Person(n, a), Employee(id) {}

    void displayManagerInfo() {
        displayPersonInfo();
        displayEmployeeInfo();
    }
};

int main() {
    Manager manager("John", 35, 12345);
    manager.displayManagerInfo();

    return 0;
}

在这个示例中,我们定义了一个 Manager 类,它同时继承自 PersonEmployeeManager 类拥有 PersonEmployee 的所有成员,可以调用它们的成员函数。


以上就是 C++ 程序的继承和派生类的基础知识点了。包括不同的继承方式和多重继承。继承是面向对象编程中的一个重要特性,它允许我们创建一个新的类,该类继承一个或多个现有类的属性和方法,从而实现代码的重用和扩展。

都看到这里了,点个赞再走呗朋友~

加油吧,预祝大家变得更强!

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值