数据抽象是面向对象编程中的一个核心概念,它允许我们将复杂的数据结构和操作封装起来,只暴露出必要的接口。通过数据抽象,我们可以隐藏实现细节,使代码更加清晰、易于维护。
类与对象
类是一种用户自定义的数据类型,它将数据和对数据的操作封装在一起。类的实例称为对象,每个对象都有自己的状态和行为。
定义类
使用 class 关键字来定义一个新的类。例如:
// www.javascriptcn.com code example
class Car {
private:
int speed;
std::string color;
public:
void setSpeed(int newSpeed) {
speed = newSpeed;
}
int getSpeed() const {
return speed;
}
void setColor(const std::string& newColor) {
color = newColor;
}
std::string getColor() const {
return color;
}
};在这个例子中,Car 类有两个私有成员变量 speed 和 color,以及四个公有成员函数 setSpeed、getSpeed、setColor 和 getColor。
创建对象
一旦类被定义,我们就可以创建该类的对象。例如:
Car myCar;
myCar.setSpeed(60);
myCar.setColor("Red");封装
封装是数据抽象的一个重要方面,它指的是将数据和操作这些数据的方法组合成一个单独的单元,并且限制外部对这些数据的访问。封装有助于保护数据不被意外修改,并且可以确保数据的一致性和完整性。
私有和公有成员
在类中,成员变量和成员函数可以被声明为私有的或公有的。私有成员只能在类的内部访问,而公有成员可以在类的外部访问。
// www.javascriptcn.com code example
class BankAccount {
private:
double balance;
public:
void deposit(double amount) {
balance += amount;
}
double getBalance() const {
return balance;
}
};在这个例子中,balance 是一个私有成员变量,只能通过 deposit 和 getBalance 方法进行访问。
访问控制
除了 private 和 public 之外,C++ 还提供了 protected 关键字,用于控制类的继承层次内的访问权限。
使用友元
有时,我们需要允许某些非成员函数或类访问类的私有成员。这时可以使用 friend 关键字。
// www.javascriptcn.com code example
class BankAccount {
private:
double balance;
public:
void deposit(double amount) {
balance += amount;
}
friend bool isNegativeBalance(const BankAccount& account);
};
bool isNegativeBalance(const BankAccount& account) {
return account.balance < 0;
}在这个例子中,isNegativeBalance 函数被声明为 BankAccount 类的友元函数,因此它可以访问 BankAccount 的私有成员 balance。
继承
继承是面向对象编程的另一个基本特性,它允许我们创建一个新类,这个新类可以继承现有类的属性和方法。新类被称为派生类或子类,而被继承的类被称为基类或父类。
基本继承
使用 : 关键字来指定基类。例如:
// www.javascriptcn.com code example
class SportsCar : public Car {
private:
int turboBoost;
public:
SportsCar() : turboBoost(0) {}
void boostTurbo(int level) {
turboBoost = level;
}
int getTurboBoost() const {
return turboBoost;
}
};在这个例子中,SportsCar 类继承了 Car 类的所有公有成员,并添加了一个新的私有成员 turboBoost 以及相应的访问方法。
多重继承
C++ 支持多重继承,这意味着一个派生类可以从多个基类继承属性和方法。
// www.javascriptcn.com code example
class ElectricCar : public Car {
private:
bool isCharging;
public:
ElectricCar() : isCharging(false) {}
void startCharging() {
isCharging = true;
}
void stopCharging() {
isCharging = false;
}
bool isCarCharging() const {
return isCharging;
}
};
class HybridCar : public Car, public ElectricCar {
private:
// HybridCar 可以拥有 Car 和 ElectricCar 的所有属性和方法
};在这个例子中,HybridCar 类同时继承了 Car 和 ElectricCar,从而拥有了两者的全部功能。
多态
多态是指同一个函数调用在不同的上下文中表现出不同的行为。C++ 中的多态主要通过虚函数来实现。
虚函数
虚函数允许我们在基类中声明一个函数,然后在派生类中重写这个函数。当通过基类指针或引用调用这个函数时,实际执行的是派生类中的版本。
// www.javascriptcn.com code example
class Vehicle {
public:
virtual void drive() {
std::cout << "Driving a generic vehicle." << std::endl;
}
};
class Car : public Vehicle {
public:
void drive() override {
std::cout << "Driving a car." << std::endl;
}
};
class Motorcycle : public Vehicle {
public:
void drive() override {
std::cout << "Driving a motorcycle." << std::endl;
}
};
void testDrive(Vehicle* vehicle) {
vehicle->drive();
}
int main() {
Vehicle* car = new Car();
Vehicle* bike = new Motorcycle();
testDrive(car); // 输出: Driving a car.
testDrive(bike); // 输出: Driving a motorcycle.
delete car;
delete bike;
return 0;
}在这个例子中,Vehicle 类中的 drive 函数被声明为虚函数。Car 和 Motorcycle 类分别重写了 drive 函数。当通过 testDrive 函数调用 drive 时,实际执行的是传递对象对应的版本。
纯虚函数
纯虚函数是一种特殊的虚函数,它没有具体的实现,而是强制派生类必须提供其实现。
// www.javascriptcn.com code example
class Animal {
public:
virtual void makeSound() const = 0; // 纯虚函数
};
class Dog : public Animal {
public:
void makeSound() const override {
std::cout << "Woof!" << std::endl;
}
};
class Cat : public Animal {
public:
void makeSound() const override {
std::cout << "Meow!" << std::endl;
}
};在这个例子中,Animal 类有一个纯虚函数 makeSound。Dog 和 Cat 类必须实现 makeSound 函数。
总结
数据抽象是面向对象编程的基础,通过类和对象的概念,我们可以将复杂的问题分解为更简单的部分。封装、继承和多态是数据抽象的重要组成部分,它们共同构成了强大的面向对象编程范式。
接下来,我们可以继续探讨其他重要的 C++ 面向对象编程概念,如模板、异常处理等。