代码实现
#include <iostream>
class A {
public:
int a;
void funcA() {
std::cout << "This is funcA of class A" << std::endl;
}
};
class B {
public:
int b;
void funcB() {
std::cout << "This is funcB of class B" << std::endl;
}
};
template<typename T1, typename T2>
class C {
public:
T1 obj1;
T2 obj2;
int c;
void funcC() {
std::cout << "This is funcC of class C" << std::endl;
}
};
模板在代码复用中的优势
- 类型无关性:模板允许编写与类型无关的代码,这样可以通过一次编写代码,应用于多种不同的数据类型,大大提高了代码的复用性。例如,上述代码中的
C
类模板可以接受任意类型的T1
和T2
,不仅仅局限于A
和B
类。
- 编译期实例化:模板代码在编译期进行实例化,根据实际使用的类型生成具体的代码,避免了运行时的额外开销,提高了效率。
- 强类型检查:模板在编译期进行类型检查,确保了代码的类型安全性,减少了运行时错误的可能性。
组合与继承在代码复用场景下的不同适用情况
- 组合:
- 适用场景:当需要在一个类中复用其他类的功能,但又不希望建立严格的“是一个”(is - a)关系时,组合是更好的选择。例如,
C
类复用A
和B
类的功能,C
类并不“是一个”A
或B
,只是使用它们的功能,组合方式更加灵活,并且可以在运行时动态地改变所组合的对象。
- 优点:组合避免了继承带来的紧密耦合关系,使得代码更加灵活,易于维护和扩展。同时,组合可以复用多个不同类的功能,而继承只能从一个父类继承。
- 缺点:可能需要编写更多的转发代码来暴露组合对象的接口。
- 继承:
- 适用场景:当存在明显的“是一个”关系时,继承是合适的选择。例如,
Dog
类继承自Animal
类,因为Dog
“是一个”Animal
,Dog
类可以继承Animal
类的属性和方法。
- 优点:代码复用性高,子类可以直接使用父类的属性和方法,代码简洁。
- 缺点:继承建立了强耦合关系,父类的修改可能会影响到子类,导致代码的维护成本增加。同时,继承具有单一继承的局限性,一个子类只能有一个直接父类。