融汇贯通:C++类的继承探索

简介: 融汇贯通:C++类的继承探索

1. 继承的概念与派生类的声明

1.1 继承的概念

继承是面向对象编程中的重要概念,通过继承可以在已有类(称为父类或基类)的基础上,创建新的类(称为子类或派生类),从而实现类之间的代码重用和扩展。继承分为单继承和多继承两种方式。


1.2 派生类的声明

派生类是通过继承基类而创建的新类,派生类具有基类的所有成员(除了构造函数和析构函数),并且可以在派生类中添加新的成员和方法。派生类的使用关键字"class",后面紧跟派生类的名称,然后使用冒号":"来指定继承的基类。


【例1-1】类的继承案例

下面是一个简单的代码示例,展示了如何声明派生类和继承基类的成员,并展示了派生类对象的不同成员的使用。

#include <iostream>
using namespace std;
// 基类
class Animal {
public:
    void eat() {
        cout << "Animal可以吃东西" << endl;
    }
protected:
    void sleep() {
        cout << "Animal在睡觉" << endl;
    }
};
// 派生类
class Dog : public Animal {
public:
    void bark() {
        cout << "狗在叫" << endl;
    }
};
int main() {
    Dog dog;
    dog.eat(); // 派生类对象可以访问基类的公有成员
    dog.sleep(); // 派生类对象可以访问基类的受保护成员
    dog.bark(); // 派生类对象可以访问自己的成员
    return 0}

运行结果:

Animal可以吃东西
Animal在睡觉
狗在叫

代码分析:

在这个例子中,Animal是基类,Dog是派生类。派生类Dog继承了基类Animal的所有公有成员和受保护成员,并且还添加了自己的成员bark。在主函数中,我们创建了一个派生类对象dog,通过该对象可以访问派生类的成员bark,也可以通过基类对象访问基类的成员eat和sleep。


2. 类的继承方式:

在C++中,类的继承方式有三种:公有继承、保护继承和私有继承。继承是面向对象编程的重要特性,它允许一个类派生出新的类,并继承父类的成员函数和成员变量。


2.1 公有继承

公有继承是最常用的一种继承方式。在公有继承中,基类的公有成员依然可以被派生类的成员函数访问和使用。


2.2 保护继承

保护继承指的是在派生类中,基类的公有成员变为派生类的保护成员。在保护继承中,基类的保护成员只能被派生类及其子类访问和使用。


【例1-2】保继承案例代码及分析:

#include<iostream>
using namespace std;
class Base {
:
    int num;
public:
    Base(int n) {
        num = n;
        cout << "Base构造函数" << endl;
    }
    void show() {
        cout << "Base类的成员num为:" << num << endl;
    }
};
class Derived : protected Base {
public:
    Derived(int n) : Base(n) {
        cout << "Derived构造函数" << endl;
    }
    void display() {
        show(); // 可以访问基类的保护成员函数
        cout << "Derived类的成员num为:" << num << endl; // 可以访问基类的保护成员变量
    }
};
int main() {
    Derived obj(18);
    obj.display();
    return ;
}

代码运行结果:

Base构造函数
Derived构造函数
Base类的成员num为:18
Derived类的员num为:18

代码分析:


首先,我们定义了两个类:Base和Derived。

类Base具有一个保护成员变量num和一个公有成员函数show(),用于显示num的值。

类Derived通过protected关键字进行保护继承,意味着基类Base的所有公有成员变为派生类Derived的保护成员。

在主函数main中我们创建了一个Derived类的对象obj,并传入参数18。

当对象obj被创建时,首先调用基类Base的构造函数,初始化基类的成员num。

然后调用派生类Derived的构造函数,没有特殊的初始化操作。

最后,调用派生类Derived的display()函数,该函数可以访问基类Base的保护成员函数show()和成员变量num,并输出对应的值。

总结:

本例展示了保护继承的基本使用方法,通过保护继承,基类的公有成员变为派生类的保护成员,只有派生类及其子类可以访问和使用这些成员。这种继承方式常用于需要将基类的实现细节隐藏起来的情况。需要注意的是,保护继承和私有继承都会改变基类成员的访问权限,因此需要根据实际需求来选择继承方式。


2.3 私继承

私有继承(private inheritance)是一种继承方式,其中派生类可以继承基类的私有成员变量和私有成员函数。私有成员只能在基类的成员函数中访问,派生类中无法直接访问。

// 基类
class BaseClass {
private:
    int privateVar;
    void privateFunc() {
        cout << " is a private function." << endl;
    }
};
// 派生类
class DerivedClass : private BaseClass {
    // DerivedClass从BaseClass中继承了privateVar和privateFunc
};
int main() {
    DerivedClass obj;
    obj.privateVar = 10; // 不能访问继承自基类的私有变量,编译错误
    obj.privateFunc(); // 不能调用继承自基类的私有函数,编译错误
    return 0;
}

2.4 综合实例

【例1-3】设计钟表类与闹表类

// 钟表
class Clock {
private:
    int hour;
    int minute;
    int second;
public:
    Clock(int h, int m, int s) {
        hour = h;
        minute = m;
        second = s;
    }
    void displayTime() {
        cout << "Time: " << hour << ":" << minute << ":" << second << endl;
    }
};
 闹表类
class AlarmClock : private Clock {
private:
    int alarmHour;
    int alarmMinute;
public:
    AlarmClock(int h, int m, int s, int alarmH, int alarmM) : Clock(h, m, s) {
        alarmHour = alarmH;
        alarmMinute = alarmM;
    }
    void displayAlarmTime() {
        cout << "Alarm Time: " << alarmHour << ":" << alarmMinute << endl;
       void setAlarm(int h, int m) {
        alarmHour = h;
        alarmMinute = m;
    }
    bool isAlarmTime() {
        if (hour == alarmHour && minute == alarmMinute) {
            return true;
        } else {
            return false;
        }
    }
};
int main() {
    AlarmClock alarmClock(8, 30, 0, 8, 30);
    alarmClock.displayTime();
    alarmClock.displayAlarmTime();
    alarmClock.setAlarm(9, 0);
    if (alarmClock.isAlarmTime()) {
        cout << "It's time to wake up!" << endl;
    } else {
        cout << "Alarm is not triggered." << endl;
    }
    return 0;
}

3. 派生类的构造过程和析构过程

3.1 派生类的构造过程

【例1-4】演示派生类的构造过程的案例


代码实例:

#include <iostream>
using namespace std;
// 基类
class Base {
public:
    Base() {
        cout << "Base类的构造函数被调用" << endl;
    }
};
// 派生类
class Derived : public Base {
public:
    Derived() {
        cout << "Derived类的构造函数被调用" << endl;
    }
};
int main() {
    Derived derivedObj; // 创建派生类对象
    return 0;
}

代码运行结果:

Base类的构造函数被调用
Derived类的构造函数被调用

代码分析:


在派生类的构造函数中,首先会调用基类的构造函数,然后再执行派生类自身的构造函数。在本例中,创建了一个派生类对象Derived,首先会调用基类Base的构造函数,然后再调用派生类Derived的构造函数。


3.2 派生类的析构过程

【例1-5】演示派生类的析构过程的案例


代码实例:

#include <iostream>
using namespace std;
// 基类
class Base {
public:
    Base() {
        cout << "Base类的构造函数被调用" << endl;
    }
    ~Base() {
        cout << "Base类的析构函数被调用" << endl;
    }
};
// 派生类
class Derived : public Base {
public:
    Derived() {
        cout << "Derived类的构造函数被调用" << endl;
    }
    ~Derived() {
        cout << "Derived类的析构函数被调用" << endl;
    }
};
int main() {
    Derived derivedObj; // 创建派生类对象
    return 0;
}

代码运行结果:

Base类的构造函数被调用
Derived类的构造函数被调用
Derived类的析构函数被调用
Base类的析构函数被调用

代码分析:


在销毁派生类对象时,析构函数的调用顺序与构造函数的调用顺序相反。在本例中,析构派生类对象derivedObj时,首先会调用派生类Derived的析构函数,然后再调用基类Base的析构函数。


3.3 综合实例

【例1-6】设计图形的相关类


代码实例:

#include <iostream>
using namespace std;
// 图形类
class Shape {
public:
    Shape() {
        cout << "Shape类的构造函数被调用" << endl;
    }
    virtual ~Shape() {
        cout << "Shape类的析构函数被调用" << endl;
    }
};
// 矩形类
class Rectangle : public Shape {
public:
    Rectangle() {
        cout << "Rectangle类的构造函数被调用" << endl;
    }
    ~Rectangle() {
        cout << "Rectangle类的析构函数被调用" << endl;
    }
};
// 圆形类
class Circle : public Shape {
public:
    Circle() {
        cout << "Circle类的构造函数被调用" << endl;
    }
    ~Circle() {
        cout << "Circle类的析构函数被调用" << endl;
    }
};
int main() {
    Shape* shape1 = new Rectangle(); // 创建矩形对象
    Shape* shape2 = new Circle(); // 创建圆形对象
    delete1;
    delete shape2    return 0;
}

代码运行结果:

Shape类的构造函数被调用
Rectangle类的构造函数被调用
Shape类的构造函数被调用
Circle类的构造函数被调用
Circle类的析构函数被调用
Shape类的析构函数被调用
Rectangle类的析构函数被调用
Shape类的析构函数被调用

代码分析:


在综合实例中,我们设计了一个基类Shape和两个派生类Rectangle和。在main函数中,通过指针创建了一个矩形对象和一个圆形对象,并且在最后使用delete关键字释放了内存。程序的执行过程中,首先会调用基类Shape的构造函数,然后再调用派生类自身的构造函数,然后在释放内存时,会先调用派生类的析构函数,再调用基类Shape的析构函数。


4. 多继承简介

在C++中,多继承是指一个派生类可以从多个基类中继承成员。这样的设计可以在一定程度上增强代码的灵活性和可重用性。多继承与单继承的主要区别在于,一个派生类可以同时拥有多个基类的特性。


【例1-7】多继承派生类的构造过程与析构过程示例代码及分析:

#include<iostream>
using namespace std;
class A {
public:
    A() {
        cout << "A的构造函数" << endl;
    }
    ~A() {
        cout << "A的析构函数" << endl;
    }
};
class B {
public:
    B() {
        cout << "B的构造函数" << endl;
    }
    ~B() {
        cout << "B的析构函数" << endl;
    }
};
class C : public A, public B {
public:
    C() {
        cout << "C的构造函数" << endl;
    }
    ~C() {
        cout << "C的析构" << endl;
    }
};
int main() {
    C obj;
    return 0;
}

代码运行结果:

A的构造函数
B的构造函数
C的构造函数
C的析构函数
B的析构函数
A的析构函数

代码分析:


首先,我们定义了三个类:A、B和C。

类A和类分别具有构函数和析构函数,用于输出相应的信息。

类C继承自A和B,通过public关键字,表示C从A和B继承的成员函数和成员变量都是公有的。

在主函数main中我们创建了一个C类的对象obj。

当对象obj被创建时,先调用类A的构造函数,再调用类B的构造函数,最后调用类C的构造函数。这个顺序是由类的继承顺序决定的。

当obj被销毁时,先调用类C的析构函数,再调用类B的析构函数,最后调用类A的析构函数。同样,这个顺序也是由类的继承顺序决定的。

总结:

本例展示了多继承的基本使用方法,以及类的构造函数和析构函数的调用顺序。在多继承中,构造函数和析构函数的调用顺序是按照继承顺序决定的,先调用基类的构造函数,后调用派生类的构造函数;析构的顺序则相反,先调用派生类的析构函数,后调用基类的析构函数。这是因为在派生类的构造函数中,需要先构造基类的成员,而在析构函数中,需要先销毁派生类的成员。需要注意的是,多继承可能引发命名冲突和菱形继承等问题,需要合理设计和使用。


相关文章
|
23天前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
63 19
|
23天前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
42 13
|
27天前
|
C++ 开发者
C++学习之继承
通过继承,C++可以实现代码重用、扩展类的功能并支持多态性。理解继承的类型、重写与重载、多重继承及其相关问题,对于掌握C++面向对象编程至关重要。希望本文能为您的C++学习和开发提供实用的指导。
53 16
|
23天前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
46 5
|
23天前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
36 5
|
23天前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
44 4
|
23天前
|
设计模式 IDE 编译器
【C++面向对象——类的多态性与虚函数】编写教学游戏:认识动物(头歌实践教学平台习题)【合集】
本项目旨在通过C++编程实现一个教学游戏,帮助小朋友认识动物。程序设计了一个动物园场景,包含Dog、Bird和Frog三种动物。每个动物都有move和shout行为,用于展示其特征。游戏随机挑选10个动物,前5个供学习,后5个用于测试。使用虚函数和多态实现不同动物的行为,确保代码灵活扩展。此外,通过typeid获取对象类型,并利用strstr辅助判断类型。相关头文件如&lt;string&gt;、&lt;cstdlib&gt;等确保程序正常运行。最终,根据小朋友的回答计算得分,提供互动学习体验。 - **任务描述**:编写教学游戏,随机挑选10个动物进行展示与测试。 - **类设计**:基类
31 3
|
3月前
|
编译器 C++ 开发者
【C++】继承
C++中的继承是面向对象编程的核心特性之一,允许派生类继承基类的属性和方法,实现代码复用和类的层次结构。继承有三种类型:公有、私有和受保护继承,每种类型决定了派生类如何访问基类成员。此外,继承还涉及构造函数、析构函数、拷贝构造函数和赋值运算符的调用规则,以及解决多继承带来的二义性和数据冗余问题的虚拟继承。在设计类时,应谨慎选择继承和组合,以降低耦合度并提高代码的可维护性。
41 1
【C++】继承
|
3月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
84 2
|
3月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
146 5