C++ 继承详解
继承是 C++ 中的面向对象编程(OOP)特性之一,它允许一个类从另一个类继承数据成员和成员函数,从而实现代码的重用和扩展。通过继承,可以创建一个新的类(子类),该子类将拥有父类(基类)的属性和行为,并可以在此基础上进行修改或扩展。
1. 继承的基本概念
- 基类(父类):被继承的类,包含一些基本的属性和方法。
- 派生类(子类):继承基类的类,除了继承基类的成员外,还可以新增自己的成员。
通过继承,派生类自动拥有基类的成员,可以对基类的成员进行访问和修改。派生类还可以重写基类的成员函数,改变其行为。
2. 继承的语法
继承的语法如下:
class DerivedClass : access_specifier BaseClass {
// 子类的成员
};
DerivedClass:派生类(子类)。BaseClass:基类(父类)。access_specifier:访问控制修饰符,决定了派生类访问基类成员的方式,可以是public、protected或private。
3. 继承的访问控制修饰符
继承的访问控制修饰符决定了派生类如何访问基类的成员:
- public 继承:基类的
public和protected成员在派生类中保持其访问权限,而private成员不可访问。 - protected 继承:基类的
public和protected成员在派生类中都变成protected,private成员不可访问。 - private 继承:基类的
public和protected成员在派生类中变成private,private成员不可访问。
4. 基本继承示例
#include <iostream>
using namespace std;
// 基类(父类)
class Animal {
public:
void speak() {
cout << "Animal makes a sound" << endl;
}
};
// 派生类(子类)
class Dog : public Animal { // 公开继承
public:
void bark() {
cout << "Dog barks" << endl;
}
};
int main() {
Dog dog;
dog.speak(); // 继承自 Animal 类
dog.bark(); // Dog 类的成员
return 0;
}
输出:
Animal makes a sound
Dog barks
5. 构造函数与继承
在继承中,派生类通常会调用基类的构造函数来初始化基类的成员。可以通过构造函数的初始化列表显式调用基类的构造函数。
示例:
#include <iostream>
using namespace std;
// 基类
class Animal {
public:
Animal(string name) { // 构造函数
this->name = name;
}
void speak() {
cout << "Animal " << name << " makes a sound" << endl;
}
private:
string name;
};
// 派生类
class Dog : public Animal {
public:
Dog(string name, int age) : Animal(name) { // 调用基类构造函数
this->age = age;
}
void display() {
cout << "Dog age: " << age << endl;
}
private:
int age;
};
int main() {
Dog dog("Buddy", 5);
dog.speak(); // 调用基类的成员函数
dog.display(); // 调用派生类的成员函数
return 0;
}
输出:
Animal Buddy makes a sound
Dog age: 5
6. 函数重写(方法重写 / 覆盖)
当派生类需要改变基类某个函数的行为时,可以在派生类中重写该函数。通过在函数声明前加上 virtual 关键字,可以实现动态绑定,即在运行时决定调用哪一个版本的函数。
示例:
#include <iostream>
using namespace std;
// 基类
class Animal {
public:
virtual void speak() { // 虚函数
cout << "Animal makes a sound" << endl;
}
};
// 派生类
class Dog : public Animal {
public:
void speak() override { // 重写基类的 speak 方法
cout << "Dog barks" << endl;
}
};
int main() {
Animal* animalPtr;
Dog dog;
animalPtr = &dog;
animalPtr->speak(); // 动态绑定,调用 Dog 类的方法
return 0;
}
输出:
Dog barks
7. 多重继承
C++ 支持多重继承,即一个派生类可以继承多个基类。这使得一个类可以同时拥有多个类的属性和行为。
示例:
#include <iostream>
using namespace std;
// 基类1
class Animal {
public:
void speak() {
cout << "Animal makes a sound" << endl;
}
};
// 基类2
class Flyable {
public:
void fly() {
cout << "Flying" << endl;
}
};
// 派生类
class Bird : public Animal, public Flyable {
public:
void chirp() {
cout << "Bird chirps" << endl;
}
};
int main() {
Bird bird;
bird.speak(); // 从 Animal 类继承
bird.fly(); // 从 Flyable 类继承
bird.chirp(); // Bird 类成员
return 0;
}
输出:
Animal makes a sound
Flying
Bird chirps
8. 虚拟继承
虚拟继承用于解决多重继承中的菱形问题。当多个基类有相同的父类时,虚拟继承可以避免重复继承相同的父类数据成员。
示例:
#include <iostream>
using namespace std;
// 基类
class Animal {
public:
Animal() { cout << "Animal constructor called" << endl; }
};
// 虚拟基类
class Mammal : virtual public Animal {
public:
Mammal() { cout << "Mammal constructor called" << endl; }
};
// 虚拟基类
class Bird : virtual public Animal {
public:
Bird() { cout << "Bird constructor called" << endl; }
};
// 派生类
class Bat : public Mammal, public Bird {
public:
Bat() { cout << "Bat constructor called" << endl; }
};
int main() {
Bat bat;
return 0;
}
输出:
Animal constructor called
Mammal constructor called
Bird constructor called
Bat constructor called
9. 继承的其他特点
- 派生类的构造函数:派生类在创建时,首先调用基类的构造函数。若基类没有默认构造函数,则派生类必须显式调用基类构造函数。
- 析构函数:当对象销毁时,派生类的析构函数会在基类析构函数之前调用。基类的析构函数通常需要被声明为虚函数,以确保正确释放内存。
总结
- 继承是 C++ 中的一个重要特性,允许一个类继承另一个类的属性和方法,实现代码复用和扩展。
- 继承的访问修饰符决定了派生类如何访问基类成员。
- 方法重写(函数重载)和虚函数允许派生类改变基类方法的行为。
- 多重继承使得派生类可以继承多个基类,增加灵活性。
- 虚拟继承解决了多重继承中的菱形继承问题。
通过继承,C++ 提供了强大的复用性和灵活性,是面向对象编程的核心特性之一。