在C++的世界里,结构体(struct)和类(class)就像一对孪生兄弟,它们有着相似的DNA却承载着不同的使命。结构体是C语言留给我们的宝贵遗产,它完美地组织了相关数据,但缺乏对行为的封装。而类,则是C++面向对象编程思想的具象化体现。
让我们从一个简单的结构体开始:
cpp复制struct Vehicle {
int power;
int distance;
};
这个结构体可以很好地存储车辆的动力和行驶距离数据,但如果我们需要让车辆"跑起来",在过程式编程中我们可能会这样写:
cpp复制void run(Vehicle& v) {
cout << "Vehicle running!" << endl;
v.distance += 10;
}
这种将数据和行为分离的方式在小规模程序中尚可接受,但随着系统复杂度增加,我们会发现数据和操作它们的函数散落在各处,难以维护。这正是类要解决的问题。
将上述结构体升级为类:
cpp复制class Vehicle {
public:
void run() {
cout << "Vehicle running!" << endl;
distance += 10;
}
int power;
int distance;
};
现在,数据和操作数据的行为被完美地封装在一起。调用方式也变得更加直观:
cpp复制Vehicle car;
car.run(); // 车辆行驶,距离自动增加
关键理解:类不仅仅是"带函数的结构体",它代表了一种将数据和行为捆绑的编程范式。这种封装性使得代码更易于理解和维护,也为后续的继承和多态奠定了基础。
访问控制是面向对象编程中封装特性的核心体现。在Vehicle类的设计中,我们需要慎重考虑每个成员的访问级别:
cpp复制class Vehicle {
public: // 对外完全开放的接口
void startEngine() { /*...*/ }
void stopEngine() { /*...*/ }
protected: // 仅对子类开放的实现细节
string engineSerialNumber;
private: // 完全封装的内部细节
string ownerID;
float fuelConsumptionRate;
};
public成员是类对外的承诺,一旦公布就应该保持稳定。例如汽车的启动/停止接口,这些方法应该设计得简单可靠,因为它们会被大量外部代码调用。
protected成员是给继承体系准备的"半成品",比如发动机序列号这样的信息,子类可能需要访问但普通用户不应该关心。
private成员则是类的绝对隐私,就像车主的身份证号和油耗系数,这些数据如果被随意修改可能导致严重问题。
在实际项目中,我遵循这些原则:
例如,更安全的fuelConsumptionRate访问方式:
cpp复制class Vehicle {
private:
float fuelConsumptionRate;
protected:
virtual float getFuelConsumption() const {
return fuelConsumptionRate;
}
public:
float calculateFuelCost(float distance) const {
return distance * getFuelConsumption();
}
};
这种设计既保护了核心数据,又为子类提供了必要的扩展点,同时对外提供了实用的计算功能。
构造函数远不止是初始化成员那么简单。一个设计良好的构造函数应该:
改进后的Vehicle构造函数:
cpp复制class Vehicle {
public:
// 委托构造函数
Vehicle() : Vehicle(0, 0, "default", "unknown") {}
// 主构造函数
explicit Vehicle(int power, int distance = 0,
string id = "", string owner = "")
: power_(power), distance_(distance) {
if(power < 0) {
throw invalid_argument("Power cannot be negative");
}
setID(id); // 使用setter方法进行验证
setOwner(owner);
}
private:
int power_;
int distance_;
string id_;
string owner_;
void setID(const string& id) {
if(!id.empty() && id.length() < 5) {
throw invalid_argument("ID too short");
}
id_ = id;
}
};
这种设计提供了多种构造方式,同时确保了数据的有效性:
cpp复制Vehicle v1; // 使用默认值
Vehicle v2(150); // 仅指定动力
Vehicle v3(200, 1000, "VH001"); // 指定多个参数
析构函数的重要性常被初学者低估。在现代C++中,我们遵循RAII(Resource Acquisition Is Initialization)原则,即资源获取即初始化。
考虑一个更复杂的Vehicle变体:
cpp复制class NetworkVehicle {
public:
NetworkVehicle() {
socket_ = new NetworkSocket(); // 获取资源
logFile_ = fopen("vehicle.log", "w");
}
~NetworkVehicle() {
delete socket_; // 释放内存
if(logFile_) {
fclose(logFile_); // 关闭文件
}
}
private:
NetworkSocket* socket_;
FILE* logFile_;
};
重要提示:在现代C++中,我们更倾向于使用智能指针和RAII包装类来避免手动资源管理。上述代码仅为展示析构函数的作用,实际项目中应该这样实现:
cpp复制class ModernNetworkVehicle {
private:
std::unique_ptr<NetworkSocket> socket_;
std::ofstream logFile_;
public:
ModernNetworkVehicle()
: socket_(std::make_unique<NetworkSocket>()),
logFile_("vehicle.log") {
// 资源自动管理,无需手动释放
}
// 不再需要显式析构函数!
};
继承方式的选择直接影响类的设计灵活性。让我们通过交通工具体系来理解不同继承方式的区别:
cpp复制// 基类
class Transportation {
public:
void transport() { cout << "Transporting..." << endl; }
protected:
float maxWeight;
};
// 公有继承 - "是一个"的关系
class Truck : public Transportation {
// transport()保持public
// maxWeight保持protected
};
// 保护继承 - "实现为"的关系
class TransportHelper : protected Transportation {
// transport()变为protected
// maxWeight保持protected
};
// 私有继承 - "用...实现"的关系
class LogisticsSystem : private Transportation {
// transport()变为private
// maxWeight变为private
};
工程实践建议:
虚继承确实能解决菱形继承问题,但它带来了额外的复杂度。让我们看一个更贴近实际的例子:
cpp复制// 交通工具基类
class Transportation {
protected:
string registrationNumber;
public:
Transportation(string reg) : registrationNumber(reg) {}
};
// 可载客接口
class PassengerCapacity {
protected:
int maxPassengers;
public:
PassengerCapacity(int max) : maxPassengers(max) {}
};
// 可载货接口
class CargoCapacity {
protected:
float maxCargoWeight;
public:
CargoCapacity(float max) : maxCargoWeight(max) {}
};
// 客车 (单继承)
class Bus : public Transportation, public PassengerCapacity {
public:
Bus(string reg, int passengers)
: Transportation(reg), PassengerCapacity(passengers) {}
};
// 货车 (单继承)
class Truck : public Transportation, public CargoCapacity {
public:
Truck(string reg, float cargo)
: Transportation(reg), CargoCapacity(cargo) {}
};
// 客货两用车 (多继承)
class Van : public Transportation,
public PassengerCapacity,
public CargoCapacity {
public:
Van(string reg, int passengers, float cargo)
: Transportation(reg),
PassengerCapacity(passengers),
CargoCapacity(cargo) {}
};
在这个设计中,我们避免了菱形继承,而是采用了更清晰的接口继承方式。每个类只继承必要的功能,没有重复的基类。
虚函数是实现运行时多态的关键。让我们扩展Vehicle类来展示多态的强大之处:
cpp复制class Vehicle {
public:
virtual void start() {
cout << "Vehicle starting..." << endl;
}
virtual void stop() {
cout << "Vehicle stopping..." << endl;
}
// 纯虚函数,使Vehicle成为抽象类
virtual float calculateEfficiency() const = 0;
virtual ~Vehicle() {} // 虚析构函数!
};
class Car : public Vehicle {
public:
void start() override {
cout << "Car engine starting..." << endl;
}
void stop() override {
cout << "Car engine stopping..." << endl;
}
float calculateEfficiency() const override {
return 15.0f; // 15 km/l
}
};
class ElectricCar : public Car {
public:
void start() override {
cout << "Electric car powering up..." << endl;
}
float calculateEfficiency() const override {
return 5.0f; // 5 km/kWh
}
};
使用示例:
cpp复制void operateVehicle(Vehicle& v) {
v.start();
// ...操作车辆...
v.stop();
cout << "Efficiency: " << v.calculateEfficiency() << endl;
}
Car myCar;
ElectricCar myEV;
operateVehicle(myCar); // 调用Car的实现
operateVehicle(myEV); // 调用ElectricCar的实现
多态最强大的应用之一是实现插件架构。假设我们正在开发一个交通模拟系统:
cpp复制class TrafficSimulator {
vector<unique_ptr<Vehicle>> vehicles;
public:
void addVehicle(unique_ptr<Vehicle> v) {
vehicles.push_back(move(v));
}
void runSimulation() {
for(auto& v : vehicles) {
v->start();
// 模拟行驶...
v->stop();
cout << "Efficiency: "
<< v->calculateEfficiency() << endl;
}
}
};
// 使用示例
TrafficSimulator sim;
sim.addVehicle(make_unique<Car>());
sim.addVehicle(make_unique<ElectricCar>());
sim.addVehicle(make_unique<Truck>());
sim.runSimulation();
这种设计允许我们轻松扩展新的车辆类型,而无需修改模拟器的主要逻辑。
C++11引入的移动语义极大地改变了我们设计类的方式。让我们为Vehicle添加移动操作:
cpp复制class Vehicle {
string registration;
unique_ptr<Engine> engine;
public:
// 移动构造函数
Vehicle(Vehicle&& other) noexcept
: registration(move(other.registration)),
engine(move(other.engine)) {}
// 移动赋值运算符
Vehicle& operator=(Vehicle&& other) noexcept {
if(this != &other) {
registration = move(other.registration);
engine = move(other.engine);
}
return *this;
}
// 禁用拷贝(假设Vehicle不可拷贝)
Vehicle(const Vehicle&) = delete;
Vehicle& operator=(const Vehicle&) = delete;
};
现代C++允许我们在编译期进行更多计算:
cpp复制class CompileTimeVehicle {
constexpr static float DEFAULT_EFFICIENCY = 12.5f;
float efficiency;
public:
constexpr explicit CompileTimeVehicle(float eff = DEFAULT_EFFICIENCY)
: efficiency(eff) {}
constexpr float getEfficiency() const { return efficiency; }
constexpr void adjustEfficiency(float factor) {
efficiency *= factor;
}
};
// 编译期计算
constexpr CompileTimeVehicle createAdjustedVehicle() {
CompileTimeVehicle v;
v.adjustEfficiency(1.2f);
return v;
}
constexpr auto bestVehicle = createAdjustedVehicle();
static_assert(bestVehicle.getEfficiency() > 12.0f);
使用工厂方法模式创建不同类型的车辆:
cpp复制class VehicleFactory {
public:
virtual unique_ptr<Vehicle> createVehicle() = 0;
virtual ~VehicleFactory() = default;
};
class CarFactory : public VehicleFactory {
public:
unique_ptr<Vehicle> createVehicle() override {
return make_unique<Car>();
}
};
class TruckFactory : public VehicleFactory {
public:
unique_ptr<Vehicle> createVehicle() override {
return make_unique<Truck>();
}
};
// 使用示例
auto factory = CarFactory();
auto myCar = factory.createVehicle();
myCar->start();
cpp复制class VehicleObserver {
public:
virtual void onSpeedChanged(float newSpeed) = 0;
virtual ~VehicleObserver() = default;
};
class Vehicle {
vector<VehicleObserver*> observers;
float currentSpeed;
public:
void attachObserver(VehicleObserver* obs) {
observers.push_back(obs);
}
void setSpeed(float speed) {
currentSpeed = speed;
notifyObservers();
}
private:
void notifyObservers() {
for(auto obs : observers) {
obs->onSpeedChanged(currentSpeed);
}
}
};
class SpeedMonitor : public VehicleObserver {
public:
void onSpeedChanged(float newSpeed) override {
cout << "Speed changed to: " << newSpeed << endl;
}
};
类的成员排列影响内存访问效率:
cpp复制// 优化前
class InefficientVehicle {
bool isRunning; // 1字节 (但可能占用4字节由于对齐)
float speed; // 4字节
bool isElectric; // 1字节 (再次导致填充)
int id; // 4字节
}; // 总计: 12字节 (实际使用6字节)
// 优化后
class EfficientVehicle {
int id; // 4字节
float speed; // 4字节
bool isRunning; // 1字节
bool isElectric; // 1字节
}; // 总计: 8字节 (无填充)
虚函数调用比普通函数调用稍慢,因为需要通过虚表指针间接调用。在性能关键代码中:
cpp复制template <typename Derived>
class VehicleBase {
public:
void start() {
static_cast<Derived*>(this)->startImpl();
}
};
class PerformanceCar : public VehicleBase<PerformanceCar> {
public:
void startImpl() {
// 高性能启动实现
}
};
确保操作要么完全成功,要么保持原始状态:
cpp复制class TransactionSafeVehicle {
string registration;
float balance;
public:
void addFunds(float amount) {
string oldReg = registration;
float oldBalance = balance;
try {
if(amount <= 0) throw invalid_argument("Amount must be positive");
// 可能抛出异常的操作
registration = validateRegistration(registration);
balance += amount;
} catch(...) {
// 恢复状态
registration = move(oldReg);
balance = oldBalance;
throw;
}
}
};
使用RAII包装器管理资源:
cpp复制class DatabaseConnection {
sqlite3* db;
class Statement {
sqlite3_stmt* stmt;
public:
explicit Statement(sqlite3* db, const char* sql) {
if(sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {
throw runtime_error("Failed to prepare statement");
}
}
~Statement() {
sqlite3_finalize(stmt);
}
// ...其他方法...
};
public:
DatabaseConnection(const char* filename) {
if(sqlite3_open(filename, &db) != SQLITE_OK) {
throw runtime_error("Failed to open database");
}
}
~DatabaseConnection() {
sqlite3_close(db);
}
void executeQuery(const char* sql) {
Statement stmt(db, sql);
// 使用stmt执行查询...
}
};
cpp复制template <typename T>
concept VehicleConcept = requires(T v) {
{ v.start() } -> std::same_as<void>;
{ v.stop() } -> std::same_as<void>;
{ v.calculateEfficiency() } -> std::convertible_to<float>;
};
template <VehicleConcept T>
class TrafficSimulator {
vector<T> vehicles;
public:
void addVehicle(T&& v) {
vehicles.push_back(forward<T>(v));
}
void runSimulation() {
for(auto& v : vehicles) {
v.start();
v.stop();
}
}
};
cpp复制class Vehicle {
string registration;
float topSpeed;
public:
auto operator<=>(const Vehicle& other) const {
if(auto cmp = registration <=> other.registration; cmp != 0) {
return cmp;
}
return topSpeed <=> other.topSpeed;
}
bool operator==(const Vehicle& other) const = default;
};
// 现在可以这样比较
Vehicle a, b;
if(a < b) { /*...*/ }
cpp复制TEST(VehicleTest, StartStopSequence) {
Car testCar;
EXPECT_NO_THROW(testCar.start());
EXPECT_TRUE(testCar.isRunning());
EXPECT_NO_THROW(testCar.stop());
EXPECT_FALSE(testCar.isRunning());
}
TEST(VehicleTest, EfficiencyCalculation) {
ElectricCar testEV;
EXPECT_GT(testEV.calculateEfficiency(), 0);
// 允许5%的误差范围
EXPECT_NEAR(testEV.calculateEfficiency(), 5.0f, 0.25f);
}
TEST(VehicleTest, InvalidPowerThrows) {
EXPECT_THROW({
Vehicle testVehicle(-100); // 负功率
}, invalid_argument);
}
cpp复制class MockVehicle : public Vehicle {
public:
MOCK_METHOD(void, start, (), (override));
MOCK_METHOD(void, stop, (), (override));
MOCK_METHOD(float, calculateEfficiency, (), (const override));
};
TEST(VehicleTest, ObserverNotification) {
MockVehicle mock;
TestObserver obs;
EXPECT_CALL(mock, start());
EXPECT_CALL(mock, stop());
mock.attachObserver(&obs);
mock.start();
mock.stop();
}
减少编译依赖,隐藏实现细节:
cpp复制// Vehicle.h
class Vehicle {
class Impl;
unique_ptr<Impl> pImpl;
public:
Vehicle();
~Vehicle();
void start();
void stop();
};
// Vehicle.cpp
class Vehicle::Impl {
Engine engine;
Transmission trans;
public:
void start() { /*...*/ }
void stop() { /*...*/ }
};
Vehicle::Vehicle() : pImpl(make_unique<Impl>()) {}
Vehicle::~Vehicle() = default;
void Vehicle::start() { pImpl->start(); }
void Vehicle::stop() { pImpl->stop(); }
将大型类分解为协作的小类:
cpp复制class Engine {
public:
virtual void ignite() = 0;
virtual void shutdown() = 0;
};
class Transmission {
public:
virtual void shiftGear(int) = 0;
};
class ModernCar {
unique_ptr<Engine> engine;
unique_ptr<Transmission> trans;
public:
ModernCar(unique_ptr<Engine> e, unique_ptr<Transmission> t)
: engine(move(e)), trans(move(t)) {}
void start() {
engine->ignite();
trans->shiftGear(1);
}
};
cpp复制class GraphicsContext {
public:
virtual void clear() = 0;
virtual void drawVehicle(const Vehicle&) = 0;
};
#ifdef WINDOWS
class WindowsGraphicsContext : public GraphicsContext {
HDC hdc;
public:
void clear() override { /* Windows实现 */ }
void drawVehicle(const Vehicle&) override { /*...*/ }
};
#elif defined(LINUX)
class LinuxGraphicsContext : public GraphicsContext {
Display* display;
public:
void clear() override { /* Linux实现 */ }
void drawVehicle(const Vehicle&) override { /*...*/ }
};
#endif
class VehicleRenderer {
unique_ptr<GraphicsContext> context;
public:
void render(const Vehicle& v) {
context->clear();
context->drawVehicle(v);
}
};
cpp复制class NetworkVehicleData {
uint32_t serialNumber;
float speed;
public:
void readFromNetwork(const char* data) {
serialNumber = ntohl(*reinterpret_cast<const uint32_t*>(data));
uint32_t temp;
memcpy(&temp, data + 4, 4);
temp = ntohl(temp);
memcpy(&speed, &temp, 4);
}
};
cpp复制class ThreadSafeVehicle {
mutable mutex mtx;
float speed;
condition_variable cv;
public:
void setSpeed(float newSpeed) {
lock_guard<mutex> lock(mtx);
speed = newSpeed;
cv.notify_all();
}
float getSpeed() const {
lock_guard<mutex> lock(mtx);
return speed;
}
void waitForSpeed(float target) const {
unique_lock<mutex> lock(mtx);
cv.wait(lock, [this, target] {
return abs(speed - target) < 0.1f;
});
}
};
cpp复制class AsyncVehicleController {
Vehicle& vehicle;
thread workerThread;
atomic<bool> running{false};
public:
explicit AsyncVehicleController(Vehicle& v) : vehicle(v) {}
~AsyncVehicleController() {
if(running) {
stop();
}
}
void start() {
running = true;
workerThread = thread([this] {
while(running) {
vehicle.update();
this_thread::sleep_for(100ms);
}
});
}
void stop() {
running = false;
if(workerThread.joinable()) {
workerThread.join();
}
}
};
识别并优化频繁执行的代码路径:
cpp复制class HighPerformanceVehicle {
array<float, 1000> sensorData;
public:
// 热路径方法 - 内联优化
float getSensorValue(size_t index) const __attribute__((always_inline)) {
assert(index < sensorData.size());
return sensorData[index];
}
// 冷路径方法
void calibrateSensors() {
// 复杂校准逻辑...
}
};
优化内存访问模式:
cpp复制class VehicleSimulation {
struct VehicleData {
float x, y; // 位置
float vx, vy; // 速度
};
vector<VehicleData> vehicles;
public:
void updatePositions(float dt) {
for(auto& v : vehicles) {
v.x += v.vx * dt;
v.y += v.vy * dt;
}
}
};
这种设计比单独的Vehicle对象数组更缓存友好,特别适合大规模模拟。
cpp复制class LoggableVehicle : public Vehicle {
ostream& logStream;
public:
explicit LoggableVehicle(ostream& log = cerr)
: logStream(log) {}
void start() override {
logStream << "[" << time(nullptr) << "] Starting vehicle\n";
Vehicle::start();
}
void stop() override {
logStream << "[" << time(nullptr) << "] Stopping vehicle\n";
Vehicle::stop();
}
};
cpp复制class DebugVehicle : public Vehicle {
public:
void start() override {
assert(!isRunning() && "Vehicle already running");
Vehicle::start();
assert(isRunning() && "Start failed");
}
void performMaintenance() {
assert(!isRunning() && "Must be stopped for maintenance");
// 维护操作...
}
};
cpp复制#define VEHICLE_STATES \
X(Idle) \
X(Starting) \
X(Running) \
X(Stopping)
class StateMachineVehicle {
public:
enum class State {
#define X(s) s,
VEHICLE_STATES
#undef X
};
string stateToString(State s) {
switch(s) {
#define X(s) case State::s: return #s;
VEHICLE_STATES
#undef X
}
return "Unknown";
}
};
cpp复制template <typename Derived>
class VehicleBase {
public:
void start() {
static_cast<Derived*>(this)->startImpl();
}
void stop() {
static_cast<Derived*>(this)->stopImpl();
}
};
class SportsCar : public VehicleBase<SportsCar> {
public:
void startImpl() {
cout << "Sports car roaring to life!" << endl;
}
void stopImpl() {
cout << "Sports car screeching to halt!" << endl;
}
};
cpp复制class EmbeddedVehicle {
uint8_t status; // 使用位域节省空间
uint16_t speed; // 0.1 km/h精度
public:
void setSpeed(float kmh) {
speed = static_cast<uint16_t>(kmh * 10);
}
float getSpeed() const {
return speed / 10.0f;
}
bool isRunning() const {
return status & 0x01;
}
void setRunning(bool running) {
if(running) status |= 0x01;
else status &= ~0x01;
}
};
cpp复制class HardwareVehicle {
struct Registers {
volatile uint32_t control;
volatile uint32_t status;
volatile uint32_t speed;
};
Registers* const regs;
public:
explicit HardwareVehicle(uintptr_t baseAddr)
: regs(reinterpret_cast<Registers*>(baseAddr)) {}
void enable() {
regs->control |= 0x01;
while(!(regs->status & 0x01)) {
// 等待硬件就绪
}
}
uint32_t getSpeed() const {
return regs->speed;
}
};
cpp复制// C++类
class Vehicle {
public:
virtual void start() = 0;
virtual void stop() = 0;
};
// C接口
extern "C" {
struct CVehicle;
CVehicle* create_vehicle();
void vehicle_start(CVehicle*);
void vehicle_stop(CVehicle*);
void destroy_vehicle(CVehicle*);
}
// 实现
struct CVehicleWrapper : public Vehicle {
// 具体实现...
};
CVehicle* create_vehicle() {
return reinterpret_cast<CVehicle*>(new CVehicleWrapper());
}
使用pybind11:
cpp复制#include <pybind11/pybind11.h>
PYBIND11_MODULE(vehicle, m) {
py::class_<Vehicle>(m, "Vehicle")
.def("start", &Vehicle::start)
.def("stop", &Vehicle::stop);
py::class_<Car, Vehicle>(m, "Car")
.def(py::init<>());
}
cpp复制class VehicleV1 {
public:
virtual void start() = 0;
virtual void stop() = 0;
};
class VehicleV2 : public VehicleV1 {
public:
virtual void setAutopilot(bool) = 0;
};
class ModernCar : public VehicleV2 {
// 实现所有接口...
};
// 使用时
void operateVehicle(VehicleV1& v) {
v.start();
if(auto v2 = dynamic_cast<VehicleV2*>(&v)) {
v2->setAutopilot(true);
}
}
cpp复制class FutureReadyVehicle {
public:
void start() {
#ifdef HAS_NEW_FEATURE
enhancedStart();
#else
legacyStart();
#endif
}
private:
void legacyStart() { /*...*/ }
void enhancedStart() { /*...*/ }
};