?
目录
当涉及到代码重用时,继承和组合是两种常见的机制。下面将更详细地介绍它们的特点、使用方式以及各自的优缺点。
class
或struct
关键字定义类,在定义派生类时,使用冒号:
指定继承关系。在继承中,派生类可以访问父类的公有成员,但不能访问私有成员。在选择使用继承还是组合时,需要考虑以下因素:
- 类的关系:如果存在一种“is-a”的关系,即派生类是基类的一种特殊形式,可以选择使用继承。例如,
Dog
可以被视为Animal
的一种特殊类型。- 代码重用程度:如果需要重用大量基类代码,可以选择继承。继承允许派生类直接使用基类的功能,减少了代码编写的工作量。
- 灵活性要求:如果需要更灵活的类关系和低耦合度,可以选择组合。组合允许动态替换成员对象,提供更大的灵活性。
继承是一种通过创建一个新类来继承已有类的属性和方法的机制。在继承关系中,子类(派生类)可以继承父类(基类)的成员变量和成员函数,并且可以添加自己的特性。下面是一个简单的示例:
#include <iostream>
class Animal {
public:
void eat() {
std::cout << "Animal is eating." << std::endl;
}
};
class Dog : public Animal {
public:
void bark() {
std::cout << "Dog is barking." << std::endl;
}
};
int main() {
Dog dog;
dog.eat(); // 输出 "Animal is eating."
dog.bark(); // 输出 "Dog is barking."
return 0;
}
在这个示例中,我们定义了一个基类Animal
和一个派生类Dog
。派生类Dog
继承了基类Animal
的eat
方法,并添加了自己的bark
方法。通过创建Dog
对象,我们可以调用继承的eat
方法和派生类自己的bark
方法。
优点:
缺点:
组合是一种通过在一个类中包含另一个类的对象来实现代码重用的机制。在组合关系中,一个类(组合类)包含另一个类(成员类)的对象作为成员变量。下面是一个示例:
#include <iostream>
class Engine {
public:
void start() {
std::cout << "Engine is starting." << std::endl;
}
};
class Car {
private:
Engine engine;
public:
void start() {
engine.start();
std::cout << "Car is starting." << std::endl;
}
};
int main() {
Car car;
car.start(); // 输出 "Engine is starting." 和 "Car is starting."
return 0;
}
在这个示例中,我们定义了一个成员类Engine
和一个组合类Car
。组合类Car
包含一个Engine
对象作为成员变量,并通过调用Engine
对象的方法实现自己的功能。
优点:
缺点:
结论: 继承和组合都是C++中常用的代码重用机制,它们各有优缺点。在选择使用哪种机制时,需要根据具体的需求和设计要求进行权衡。如果需要创建一个层次结构或者重用大量基类代码,可以选择继承;如果需要更灵活的类关系和低耦合度,可以选择组合。重要的是根据实际情况选择适合的代码重用方式,并结合良好的设计原则来编写高质量的代码。
其中有两个重要的类:User
(用户)和Order
(订单)。用户可以下订单,并且一个用户可以有多个订单,因此User
类和Order
类之间存在一种关系。我们将使用继承和组合两种方式来设计这两个类之间的关系。
#include <iostream>
#include <string>
// 用户类
class User {
private:
std::string name;
public:
User(const std::string& name) : name(name) {}
void setName(const std::string& newName) {
name = newName;
}
std::string getName() const {
return name;
}
virtual void displayInfo() const {
std::cout << "User: " << name << std::endl;
}
};
// 订单类,继承自用户类
class Order : public User {
private:
std::string orderId;
public:
Order(const std::string& name, const std::string& orderId)
: User(name), orderId(orderId) {}
void setOrderId(const std::string& newOrderId) {
orderId = newOrderId;
}
std::string getOrderId() const {
return orderId;
}
void displayInfo() const override {
std::cout << "User: " << getName() << ", OrderId: " << orderId << std::endl;
}
};
int main() {
User user("John");
Order order("John", "12345");
user.displayInfo();
order.displayInfo();
return 0;
}
Order
类继承自User
类。通过继承,Order
类获得了User
类的成员函数和成员变量,并且可以添加自己的特性。我们重写了displayInfo()
函数,以便在Order
类中显示订单相关信息。4.1.2组合方式#include <iostream>
#include <string>
// 用户类
class User {
private:
std::string name;
public:
User(const std::string& name) : name(name) {}
void setName(const std::string& newName) {
name = newName;
}
std::string getName() const {
return name;
}
void displayInfo() const {
std::cout << "User: " << name << std::endl;
}
};
// 订单类,组合了用户类对象
class Order {
private:
std::string orderId;
User user;
public:
Order(const std::string& name, const std::string& orderId)
: user(name), orderId(orderId) {}
void setOrderId(const std::string& newOrderId) {
orderId = newOrderId;
}
std::string getOrderId() const {
return orderId;
}
void displayInfo() const {
std::cout << "User: " << user.getName() << ", OrderId: " << orderId << std::endl;
}
};
int main() {
User user("John");
Order order("John", "12345");
user.displayInfo();
order.displayInfo();
return 0;
}
在这个例子中,Order
类包含了一个User
类的对象作为成员变量。通过组合,Order
类可以调用User
类的方法来处理用户相关的操作。
总结: 在这个案例中,我们展示了继承和组合两种不同的代码重用方式。继承适用于存在"是一种"关系的类,并且可以直接使用基类的成员函数和成员变量。组合适用于存在"有一个"关系的类,其中一个类作为另一个类的成员变量,通过调用成员对象的方法来实现功能。选择使用继承还是组合取决于具体的需求和设计目标,需要权衡各自的优缺点来做出决策。