Skip to content

C++ 面向对象

C++ 创建的一个主要动机是将面向对象的能力添加到 C 语言中。OOP 是一种编程范式(programming paradigm),基于“对象”的概念,对象可以包含以字段(通常称为属性或特性)形式存在的数据,以及以过程(通常称为方法)形式存在的代码。

在 OOP 中,我们将现实世界或抽象实体建模为对象。例如,一个 Car 对象可能具有 color、make、model 等属性,以及 startEngine()、accelerate()、brake() 等方法。这种方法通过围绕数据组织代码,有助于管理大型软件系统中的复杂性。

有几个核心概念支撑着面向对象编程:

类是创建对象的蓝图或模板。它定义了该类的所有对象将拥有的属性(数据成员)和方法(成员函数)。定义一个类本身并不会创建对象,而是指定了该类型对象的外观和行为方式。

// Class definition (blueprint) // 类定义(蓝图)
class Dog {
public:
// Data members (properties) // 数据成员(属性)
std::string breed;
int age;
std::string name;
// Member functions (methods) // 成员函数(方法)
void bark() {
std::cout << name << " says Woof!\n"; // 输出:[名字] 说 汪汪!
}
};

对象是类的一个实例(instance)。它是根据类蓝图创建的、驻留在内存中的具体实体。每个对象都有自己的类数据成员的副本(除非它们是静态的)。您通过调用对象的方法来与其交互。

// Creating objects (instances) of the Dog class // 创建 Dog 类的对象(实例)
Dog myDog;
myDog.name = "Buddy";
myDog.breed = "Golden Retriever";
myDog.age = 3;
Dog anotherDog;
anotherDog.name = "Lucy";
myDog.bark(); // Output: Buddy says Woof! // 输出:Buddy 说 汪汪!
anotherDog.bark(); // Output: Lucy says Woof! // 输出:Lucy 说 汪汪!

封装意味着将数据(属性)和操作该数据的方法捆绑在一个单元(类/对象)内。它还包括控制对对象内部状态的访问,通常通过将数据成员设为 private 或 protected,并提供 public 方法(获取器 getters 和设置器 setters)以受控的方式与数据交互。这保护了对象的内部状态免受意外的外部修改,这个概念称为数据隐藏(data hiding)。

class BankAccount {
private:
double balance; // Data is hidden // 数据被隐藏
public:
BankAccount(double initialBalance) : balance(initialBalance) {} // 构造函数
void deposit(double amount) { // Controlled access // 受控访问
if (amount > 0) {
balance += amount;
}
}
double getBalance() const { // Controlled access // 受控访问
return balance;
}
};

抽象意味着隐藏复杂的实现细节,只向用户暴露基本特性或接口。用户通过对象的公共方法与对象交互,而无需了解这些方法内部是如何实现的。想想驾驶汽车:您使用方向盘、踏板和换挡杆(接口),而无需理解其下的复杂机械(实现)。在 C++ 中,类通过其公共接口(public 方法,有时也包括数据)提供抽象。

继承允许一个新类(派生类 derived class)获得现有类(基类 base class)的属性和方法。这促进了代码重用并建立了“is-a”关系(例如,Square 是一个 Shape)。派生类可以通过添加新的成员或修改继承的行为(方法重写 method overriding)来扩展基类。

class Animal { // Base class // 基类
public:
virtual void speak() const { std::cout << "Animal sound\n"; } // 虚函数,表示动物声音
virtual ~Animal() = default; // 虚析构函数,确保正确清理内存
};
class Cat : public Animal { // Derived class // 派生类
public:
void speak() const override { std::cout << "Meow\n"; } // Overrides base method // 重写基类方法
};

多态(来自希腊语,意为“多种形式”)允许将不同类的对象视为通用基类的对象。C++ 中最常见的形式是运行时多态(runtime polymorphism),通过 virtual 函数和继承实现。这意味着对成员函数的调用将根据运行时实际引用的对象的实际类型执行不同的函数,通常通过基类指针或引用。

void makeAnimalSpeak(const Animal& animal) { // Takes a reference to the base class // 接收基类引用
animal.speak(); // Calls the correct 'speak' based on the actual object type // 根据实际对象类型调用正确的 'speak'
}
Cat myCat;
Animal* animalPtr = &myCat;
makeAnimalSpeak(myCat); // Output: Meow // 输出:喵
animalPtr->speak(); // Output: Meow (through base pointer) // 输出:喵 (通过基类指针)

函数重载(Function overloading)和运算符重载(operator overloading)是编译时多态(compile-time polymorphism)的形式。它们允许在同一作用域内存在同名但参数列表不同(对于函数)或操作数类型不同(对于运算符)的多个函数或运算符。编译器根据调用 site 提供的参数或操作数来确定调用哪个版本。

int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
// The compiler chooses based on arguments: // 编译器根据参数选择:
add(5, 3); // Calls the int version // 调用 int 版本
add(2.5, 3.1); // Calls the double version // 调用 double 版本

OOP 提供了一套强大的工具,用于设计灵活、可维护和可重用的软件。