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