c++ - 模板化函数或带有指向基类的指针的函数
问题描述
当我想对几种不同类型的输入类使用一个函数(这里称为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
)。
推荐阅读
- python - Python计算文本文件中包含数字的行数
- casting - 不理解类型转换的 F# 语法
- c# - 如何使用背后代码(MVVM)中的 SearchBar 过滤 ListView
- perl - 在 Perl 中,如何访问在另一个包中定义的变量
- java - 在java中将对象转换为接口并返回
- python - 为什么 concurrent.futures 的 submit() 不立即将控制权返回给主程序?
- python - 如何在python中的变量中创建和存储以下内容?
- sml - 检查字符串是否包含 SML 中的帕斯卡整数
- sql - 单个分隔列上的 T-SQL `FOR JSON`
- google-apps-script - 如何在 Google Scripts 的电子邮件中发送表格?