跳到主要内容

C++ 继承

提示
  1. 继承概念:C++中的继承是面向对象编程的关键特性之一,允许从已有的类(基类)创建新类(派生类)。派生类继承了基类的特性,并且可以有自己的附加特性。
  2. is-a关系:继承是一种is-a关系,我们只在两个类之间存在is-a关系时使用继承。例如,“狗是动物”(Dog is an Animal)或“橙子是水果”(Orange is a Fruit)。
  3. 访问模式和成员访问:在继承中可以使用publicprivateprotected关键字来定义访问模式。public继承保持基类成员的访问级别,private继承使所有基类成员在派生类中变为private,而protected继承则将基类的public成员转换为派生类中的protected成员。

继承是C++面向对象编程的关键特性之一。它允许我们从一个已存在的类(基类)创建一个新的(派生类)。

派生类继承了基类的特性并且可以有其自己的额外特性。例如,

class Animal {
// eat() 函数
// sleep() 函数
};

class Dog : public Animal {
// bark() 函数
};

这里,Dog 类是从 Animal 类派生的。由于 Dog 是从 Animal 派生的,Animal 的成员对 Dog 是可访问的。

Dog 类继承自 Animal 类

注意在从 Animal 继承 Dog 时使用了关键字 public

class Dog : public Animal {...};

我们也可以使用 privateprotected 关键字代替 public。我们将在本教程后面学习使用 privatepublicprotected 的区别。

是一种关系

继承是一种是一种关系。我们只有在两个类之间存在是一种关系时才使用继承。

以下是一些例子:

  • 汽车是一种交通工具。
  • 橙子是一种水果。
  • 外科医生是一种医生。
  • 狗是一种动物。

示例 1:C++ 继承的简单示例

// C++ 程序演示继承

#include <iostream>
using namespace std;

// 基类
class Animal {

public:
void eat() {
cout << "我能吃!" << endl;
}

void sleep() {
cout << "我能睡!" << endl;
}
};

// 派生类
class Dog : public Animal {

public:
void bark() {
cout << "我能叫!汪汪!!" << endl;
}
};

int main() {
// 创建 Dog 类的对象
Dog dog1;

// 调用基类的成员
dog1.eat();
dog1.sleep();

// 调用派生类的成员
dog1.bark();

return 0;
}

输出

我能吃!
我能睡!
我能叫!汪汪!!

这里,dog1(派生类 Dog 的对象)可以访问基类 Animal 的成员。这是因为 Dog 继承自 Animal

// 调用 Animal 类的成员
dog1.eat();
dog1.sleep();

C++ protected 成员

访问修饰符 protected 在C++继承中特别相关。

private 成员一样,protected 成员在类的外部无法访问。然而,它们可以被派生类友元类/函数访问。

如果我们想要隐藏类的数据,但仍然希望这些数据被其派生类继承,就需要 protected 成员。

要了解更多关于 protected,请参阅我们的 C++ 访问修饰符 教程。

示例 2:C++ protected 成员

// C++ 程序演示 protected 成员

#include <iostream>
#include <string>
using namespace std;

// 基类
class Animal {

private:
string color;

protected:
string type;

public:
void eat() {
cout << "我能吃!" << endl;
}

void sleep() {
cout << "我能睡!" << endl;
}

void setColor(string clr) {
color = clr;
}

string getColor() {
return color;
}
};

// 派生类
class Dog : public Animal {

public:
void setType(string tp) {
type = tp;
}

void displayInfo(string c) {
cout << "我是一个 " << type << endl;
cout << "我的颜色是 " << c << endl;
}

void bark() {
cout << "我能叫!汪汪!!" << endl;
}
};

int main() {
// 创建 Dog 类的对象
Dog dog1;

// 调用基类的成员
dog1.eat();
dog1.sleep();
dog1.setColor("黑色");

// 调用派生类的成员
dog1.bark();
dog1.setType("哺乳类");

// 使用 dog1 的 getColor() 作为参数
// getColor() 返回字符串数据
dog1.displayInfo(dog1.getColor());

return 0;
}

输出

我能吃!
我能睡!
我能叫!汪汪!!
我是一个哺乳类
我的颜色是黑色

这里,变量 type 是 protected 的,因此可以从派生类 Dog 访问。我们可以看到这一点,因为我们在 Dog 类中使用函数 setType() 初始化了 type

另一方面,private 变量 color 不能在 Dog 中初始化。

class Dog : public Animal {

public:
void setColor(string clr) {
// 错误:成员 "Animal::color" 不可访问
color = clr;
}
};

同样,由于 protected 关键字隐藏数据,我们不能直接从 DogAnimal 类的对象访问 type。

// 错误:成员 "Animal::type" 不可访问
dog1.type = "哺乳类";

C++ 继承中的访问模式

在我们之前的教程中,我们已经学习了 C++ 访问修饰符,如 public, private, 和 protected

到目前为止,我们已经使用了 public 关键字来从之前存在的基类继承一个类。然而,我们也可以使用 privateprotected 关键字来继承类。例如,

class Animal {
// 代码
};

class Dog : private Animal {
// 代码
};
class Cat : protected Animal {
// 代码
};

我们继承类的各种方式被称为访问模式。这些访问模式有以下影响:

  1. public: 如果一个派生类是以 public 模式声明的,那么基类的成员被派生类继承,就像它们原来一样。
  2. private: 在这种情况下,基类的所有成员在派生类中都变成 private 成员。
  3. protected: 基类的 public 成员在派生类中变成 protected 成员。

基类的 private 成员在派生类中始终是 private 的。

要了解更多,请访问我们的 C++ public, private, protected 继承 教程。

继承中的成员函数重写

假设基类和派生类具有相同名称和参数的成员函数。

如果我们创建一个派生类的对象并尝试访问那个成员函数,将调用派生类中的成员函数而不是基类中的。

派生类的成员函数重写了基类的成员函数。

了解更多关于C++中的函数重写