
在C++面向对象编程中,继承是四大基本特性(封装、继承、多态、抽象)之一,它允许我们定义一个新类(派生类或子类)来继承另一个类(基类或父类)的属性和方法。这种机制极大地提高了代码的复用性,并使得程序结构更加清晰和易于维护。
继承是面向对象编程中的一个核心概念,它表示一种“is-a”关系。例如,狗是一种哺乳动物,哺乳动物是一种动物。在C++中,我们可以通过继承来模拟这种关系,使得子类可以拥有父类的属性和方法,同时还可以定义自己的特有属性和方法。
在C++中,继承的基本语法如下:
class DerivedClass : access-specifier BaseClass {
// 派生类的成员
};其中,access-specifier是访问修饰符,可以是public、protected或private,它决定了基类成员在派生类中的访问权限。
public:基类的公有成员和保护成员在派生类中保持其原有的访问权限,基类的私有成员在派生类中不可见。protected:基类的公有成员和保护成员在派生类中变为保护成员,基类的私有成员在派生类中不可见。private:基类的公有成员和保护成员在派生类中变为私有成员,基类的私有成员在派生类中不可见。以下是一个简单的单继承示例,展示了如何通过继承来实现属性和方法的复用:
#include <iostream>
#include <string>
using namespace std;
// 基类(父类)
class Animal {
public:
Animal(string name) : name(name) {}
void eat() {
cout << name << " is eating." << endl;
}
void sleep() {
cout << name << " is sleeping." << endl;
}
protected:
string name; // 动物的名字
};
// 派生类(子类)
class Dog : public Animal {
public:
Dog(string name, string breed) : Animal(name), breed(breed) {}
void bark() {
cout << "Woof! Woof!" << endl;
}
// 重新定义父类方法
void eat() {
cout << "The dog is eating dog food." << endl;
}
private:
string breed; // 狗的品种
};
int main() {
// 创建一个 Animal 对象
Animal animal("Generic Animal");
animal.eat();
animal.sleep();
cout << endl;
// 创建一个 Dog 对象
Dog dog("Buddy", "Golden Retriever");
dog.eat(); // 调用子类重写的方法
dog.sleep();
dog.bark(); // 调用子类特有的方法
return 0;
}
在继承中,基类成员的访问权限受到继承方式和基类中成员访问修饰符的共同影响。具体规则如下:
基类成员访问修饰符 | 继承方式 | 派生类中的访问权限 |
|---|---|---|
public | public | public |
public | protected | protected |
public | private | private |
protected | public | protected |
protected | protected | protected |
protected | private | private |
private | 任何方式 | 不可见 |
Animal和派生类Dog // 基类:动物
class Animal {
public:
void speak() { std::cout << "Animal sound" << std::endl; }
int age;
};
// 派生类:狗(public继承)
class Dog : public Animal {
public:
void fetch() { std::cout << "Fetching stick!" << std::endl; }
};① public继承
public→public,protected→protected)Dog是一种AnimalDog d;
d.speak(); // 合法,基类public成员在派生类中仍为public
d.age = 10; // 合法,基类public成员② protected继承
public成员在派生类中变为protectedclass Intermediate : protected Animal {
// Intermediate的子类可访问Animal的public成员(现为protected)
};③private继承
privateclass Robot : private Animal {
// Robot内部使用Animal的功能,但不对外暴露
};private成员始终无法在派生类中直接访问,只能通过基类的public或protected接口间接访问class Animal {
private:
int secret; // 派生类无法直接访问
public:
void setSecret(int s) { secret = s; } // 间接访问接口
};
class Dog : public Animal {
void accessSecret() {
// secret = 10; // 错误:无法访问基类private成员
setSecret(10); // 正确:通过基类public方法访问
}
};示例:多层继承的构造顺序
class A {
public:
A() { std::cout << "A constructor" << std::endl; }
};
class B : public A {
public:
B() { std::cout << "B constructor" << std::endl; }
};
class C : public B {
public:
C() { std::cout << "C constructor" << std::endl; }
};
int main() {
C obj; // 输出:A→B→C的构造顺序
return 0;
}
class Animal {
public:
Animal(int age) : age(age) { std::cout << "Animal constructor" << std::endl; }
int age;
};
class Dog : public Animal {
public:
Dog(int age, std::string name)
: Animal(age), name(name) { // 显式调用基类构造函数
std::cout << "Dog constructor" << std::endl;
}
std::string name;
};示例:静态成员的继承
class Base {
public:
static int staticVar;
static void staticFunc() { std::cout << "Base static func" << std::endl; }
};
int Base::staticVar = 10;
class Derived : public Base {};
int main() {
std::cout << Derived::staticVar << std::endl; // 输出10
Derived::staticFunc(); // 输出"Base static func"
return 0;
}
class Base {
public:
static int value;
};
int Base::value = 10;
class Derived : public Base {
public:
static int value; // 隐藏基类的value,但未覆盖
};
int Derived::value = 20;
int main() {
std::cout << Base::value << std::endl; // 10
std::cout << Derived::value << std::endl; // 20
std::cout << Derived::Base::value << std::endl; // 显式访问基类value,输出10
return 0;
}
::显式访问基类成员示例:函数名称隐藏
class Base {
public:
void func() { std::cout << "Base func" << std::endl; }
};
class Derived : public Base {
public:
void func(int x) { std::cout << "Derived func with int: " << x << std::endl; }
};
int main() {
Derived d;
d.func(); // 错误:Base::func()被隐藏
d.Base::func(); // 正确:显式调用基类func()
d.func(10); // 正确:调用派生类func(int)
return 0;
}
virtual时,派生类可通过相同签名的函数实现覆盖(Override)class Animal {
public:
virtual void speak() { std::cout << "Animal sound" << std::endl; }
};
class Dog : public Animal {
public:
void speak() override { // C++11的override关键字确保正确覆盖
std::cout << "Woof!" << std::endl;
}
};class Base {
public:
virtual Base* clone() { return new Base(); }
};
class Derived : public Base {
public:
Derived* clone() override { // 合法,返回Derived*(Base*的派生类型)
return new Derived();
}
};class Animal { /* ... */ };
class Mammal : public Animal { /* ... */ };
class Dog : public Mammal { /* ... */ }; // Animal → Mammal → Dog①问题描述:两个派生类继承同一基类,又共同派生出一个子类,导致基类成员在子类中存在两份副本,引发二义性问题

②示例代码(未解决的菱形继承)
class Base {
public:
int value;
};
class Derived1 : public Base {};
class Derived2 : public Base {};
class GrandDerived : public Derived1, public Derived2 {};
int main() {
GrandDerived obj;
obj.Derived1::value = 10; // 必须显式指定路径
obj.Derived2::value = 20;
return 0;
}③解决方案:虚继承(Virtual Inheritance)
使用virtual关键字声明基类,确保基类在派生类中只有一份共享副本
class Base { /* ... */ };
class Derived1 : virtual public Base {}; // 虚继承
class Derived2 : virtual public Base {}; // 虚继承
class GrandDerived : public Derived1, public Derived2 {};④虚继承的构造函数
最底层派生类(GrandDerived)负责调用虚基类(Base)的构造函数
GrandDerived() : Base(), Derived1(), Derived2() { /* ... */ }Car包含Engine对象 class Engine {
public:
void start() { std::cout << "Engine started" << std::endl; }
};
class Car {
private:
Engine engine; // 组合
public:
void startEngine() { engine.start(); }
};特性 | 继承 | 组合 |
|---|---|---|
关系类型 | is-a(如 Dog 是 Animal) | has-a(如 Car 有 Engine) |
代码耦合度 | 高(基类变更影响派生类) | 低(成员对象可独立变化) |
访问控制 | 通过继承方式控制 | 通过成员对象的接口控制 |
多态支持 | 天然支持 | 需通过接口类实现 |
class Base {
public:
virtual ~Base() { std::cout << "Base destructor" << std::endl; }
};
class Derived : public Base {
public:
~Derived() { std::cout << "Derived destructor" << std::endl; }
};
int main() {
Base* ptr = new Derived();
delete ptr; // 输出:Derived→Base析构(虚析构函数生效)
return 0;
}
class Shape {
public:
virtual double area() const = 0; // 纯虚函数
};
class Circle : public Shape {
public:
double area() const override { return 3.14 * radius * radius; }
private:
double radius;
};class Derived : public Base1, public Base2 { ... }示例:多重继承
class Flyable {
public:
void fly() { std::cout << "Flying" << std::endl; }
};
class Swimable {
public:
void swim() { std::cout << "Swimming" << std::endl; }
};
class Duck : public Flyable, public Swimable {}; // 鸭子同时会飞和游泳
int main() {
Duck d;
d.fly(); // 合法
d.swim(); // 合法
return 0;
}
template <typename T>
class Container {
public:
void add(T item) { items.push_back(item); }
protected:
std::vector<T> items;
};
class IntContainer : public Container<int> {
public:
int sum() {
int total = 0;
for (int item : items) total += item;
return total;
}
};#include <iostream>
#include <vector>
#include <string>
#include <cmath>
using namespace std;
// ====================== 抽象基类:图形 ======================
class Shape {
public:
// 纯虚函数:获取图形名称和面积
virtual string getName() const = 0;
virtual double getArea() const = 0;
// 虚析构函数确保多态析构
virtual ~Shape() {}
};
// ====================== 二维图形基类 ======================
class TwoDShape : virtual public Shape { // 使用虚继承
public:
// 构造函数接收宽和高
TwoDShape(double width, double height)
: width_(width), height_(height) {}
// 获取宽和高
double getWidth() const { return width_; }
double getHeight() const { return height_; }
protected:
double width_; // 宽度
double height_; // 高度
};
// ====================== 三维图形基类 ======================
class ThreeDShape : virtual public Shape { // 使用虚继承
public:
// 构造函数接收体积
ThreeDShape(double volume) : volume_(volume) {}
// 获取体积
double getVolume() const { return volume_; }
protected:
double volume_; // 体积
};
// ====================== 派生类:矩形(二维图形) ======================
class Rectangle : public TwoDShape {
public:
// 构造函数调用基类构造函数
Rectangle(double width, double height)
: TwoDShape(width, height) {}
// 覆盖基类虚函数
string getName() const override { return "Rectangle"; }
double getArea() const override {
return width_ * height_; // 矩形面积 = 宽×高
}
};
// ====================== 派生类:正方形(矩形的特化) ======================
class Square : public Rectangle {
public:
// 构造函数直接指定边长(宽高相等)
Square(double side) : Rectangle(side, side) {}
// 重写名称(可选,也可继承Rectangle的名称)
string getName() const override { return "Square"; }
};
// ====================== 派生类:圆形(二维图形) ======================
class Circle : public TwoDShape {
public:
// 构造函数接收半径(宽高统一为直径)
Circle(double radius) : TwoDShape(2*radius, 2*radius), radius_(radius) {}
// 覆盖基类虚函数
string getName() const override { return "Circle"; }
double getArea() const override {
return M_PI * radius_ * radius_; // 圆形面积 = πr²
}
private:
double radius_; // 半径
};
// ====================== 派生类:立方体(三维图形,基于正方形) ======================
class Cube : public ThreeDShape, public Square {
public:
// 构造函数调用三维基类和正方形基类(多重继承)
Cube(double side)
: ThreeDShape(side*side*side), Square(side) {} // 体积 = 边长³
// 覆盖基类虚函数(从Shape继承)
string getName() const override { return "Cube"; }
double getArea() const override {
return 6 * Square::getArea(); // 立方体表面积 = 6×一个面的面积
}
};
// ====================== 多态容器与遍历函数 ======================
void printShapeInfo(const vector<Shape*>& shapes) {
for (const auto* shape : shapes) {
cout << "Name: " << shape->getName()
<< ", Area: " << shape->getArea();
// 若为三维图形,额外输出体积
if (auto* threeDShape = dynamic_cast<const ThreeDShape*>(shape)) {
cout << ", Volume: " << threeDShape->getVolume();
}
cout << endl;
}
}
// ====================== 主函数:测试继承层次 ======================
int main() {
vector<Shape*> shapes;
// 添加二维图形
shapes.push_back(new Rectangle(4, 5)); // 矩形
shapes.push_back(new Square(3)); // 正方形
shapes.push_back(new Circle(2)); // 圆形
// 添加三维图形
shapes.push_back(new Cube(3)); // 立方体
// 遍历多态容器,输出信息
printShapeInfo(shapes);
// 释放内存(多态析构)
for (auto* shape : shapes) {
delete shape;
}
return 0;
}
public继承:通常用于表示“is-a”关系,保持基类接口的可见性。protected和private继承:较少使用,通常用于实现细节或特殊场景。继承是C++面向对象编程中的核心特性之一,它允许我们通过复用基类的代码来构建更加复杂和功能丰富的程序。在实际编程中,我们应根据具体需求合理设计继承层次,合理使用访问修饰符,避免命名冲突,并合理使用虚函数和多态。通过深入理解和应用继承特性,可以编写出更加清晰、健壮和易于维护的C++代码。