模板化函数或具有指向基类的指针的函数
Templated function or function with pointer to base class
当我想为几种不同类型的输入类使用一个函数(这里称为do_some_work()
/do_some_templated_work()
(并且我不想多次重写该函数时,据我所知,我可以模板化该函数,或者从基类派生所有涉及的类,并使用该基类的指针。我为这两种情况编写了一个简短的测试程序:
#include <iostream>
#include <string>
class BaseClass {
public:
BaseClass(){
class_name = std::string("Base class");
}
virtual ~BaseClass(){};
virtual double work_func(const double a, const double b) {
(void) a;
(void) b;
return 0;
};
virtual void print_class_name(void) {};
private:
std::string class_name;
};
class DerivedClassA : public BaseClass{
public:
DerivedClassA(){
class_name = std::string("Class A");
}
~DerivedClassA() override {
}
double work_func(const double a, const double b) override{
return a + b;
}
void print_class_name(void) override{
std::cout << class_name << 'n';
}
private:
std::string class_name;
};
class DerivedClassB : public BaseClass{
public:
DerivedClassB(){
class_name = std::string("Class B");
}
~DerivedClassB() override {
}
double work_func(const double a, const double b) override{
return a - b;
}
void print_class_name(void) override{
std::cout << class_name << 'n';
}
private:
std::string class_name;
};
void do_some_work(BaseClass &test_class){
test_class.print_class_name();
std::cout << test_class.work_func(5, 6) << 'n';
}
template <class T>
void do_some_templated_work(T &test_class) {
test_class.print_class_name();
std::cout << test_class.work_func(5, 6) << 'n';
}
int main()
{
std::cout << "Hello World!" << std::endl;
DerivedClassA AClass;
DerivedClassB BClass;
do_some_work(AClass);
do_some_work(BClass);
do_some_templated_work(AClass);
do_some_templated_work(BClass);
return 0;
}
在查看 ASM 代码时,我没有看到两者的直接优势(不过这可能与编译开关有关(。因此,我在这里没有考虑什么,在比较这两种方法时,这两种方法都有其优点/缺点吗?或者我是否可以将第三种方法用于相同的目的?
一般来说,第一个选项涉及虚拟调度(即在运行时跳转到正确的函数(,而第二个选项已经知道在编译时调用的正确函数。后者通常具有较少的开销,并为编译器开辟了更多的优化机会,但可能存在缺点(代码大小,指令缓存等(。性能将始终取决于细节,因此,如果您关心它,请配置文件。
开箱即用的继承无法做到的事情是,例如从work_func
返回不同类型的值 - 这就是模板闪耀的地方。
另一方面,继承(特别是在遵循 Liskov 替换原则时(可以使接口的合约/期望更加清晰(void do_some_templated_work(T &test_class)
不会告诉您T
需要实现例如print_class_name
(。
相关文章:
- 基类中的函数名称解析
- 如何通过派生类函数更改基类中的向量
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如果基类包含双指针成员,则派生类的构造函数
- C++ 继承:将子类传递给需要基类的函数并获取子类行为
- 继承和友元函数,从基类访问受保护的成员
- 使用子类覆盖基类中定义的函数
- 如何基于模板化类的基类专门化成员函数
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 使用基类指针调用基类的值构造函数的语法是什么?
- C++重载函数,一个采用基类的参数,另一个采用派生类的参数
- 如何在基类指针向量的元素上应用重载的多态函数
- 如何在不使用指针的情况下将派生类的对象作为参数传递给基类中的函数?
- 被覆盖的函数不会反映在基类中,这是正常行为吗?
- 在初始化列表之外手动调用基类的构造函数
- 重写打印函数而不是覆盖基类
- C++17 使用驱动类常量作为基类构造函数的参数来初始化基类构造函数
- C++虚拟函数:基类函数是调用的,而不是派生的
- 虚拟函数-基类指针