模板基类与正确的派生类函数调用--Effective C++ Item 43
问题描述
假设我们有这样一个业务场景,我们管理着许多公司,每个公司都有一个自己的许多日志信息需要处理,于是为了方便,我们写了一个模板类用来处理这些公司的信息,并且将这些公司的日志打印函数都设为了Static Member Function。
class CompanyA {
public:
static void Print() {
std::cout << "I am A!" << std::endl;
}
};
class CompanyB {
public:
static void Print() {
std::cout << "I am B!" << std::endl;
}
};
template<typename Company>
class Sender {
public:
void Print() {
std::cout << "Base MessageSender!" << std::endl;
Company::Print();
}
};
在写完上述代码后,我们便可以通过Sender中的Print函数来进行公司信息的打印,这看起来很好,但是假如我们使用一个派生类来继承Sender来增强这个类的功能,并希望在这个派生类中调用Sender中的Print函数,我们大概率会这么写。
template<typename T>
class MessageSender : public Sender<T> {
public:
void AugMentSenderPrint() {
// doing other augment stuff
Print();
}
};
这么写虽然看着很对,我们在派生类的AugMentSenderPrint中调用基类的Print函数,但是不幸的是这段代码99%无法通过编译。因为模板的实例化只有在其第一次被调用时才会进行,所以编译器在这里无法判断Print是否存在于基类。
解决办法
但是凡事都有解决办法,这里的话主要是有三种解决方式。
- 利用this指针
template<typename T>
class MessageSender : public Sender<T> {
public:
void AugMentSenderPrint() {
// doing other augment stuff
this->Print();
}
};
- 利用using声明
template<typename T>
class MessageSender : public Sender<T> {
public:
using Sender<T>::print;
void SenderPrint() {
Print();
}
};
- 静态绑定
template<typename T>
class MessageSender : public Sender<T> {
public:
void SenderPrint() {
Sender<T>::Print();
}
};
这三种方法中,前两种都是可以采用的方式,但是最后一种静态绑定会使得我们的程序丧失运行时的多态性,如果Print是一个虚函数的话,这种方法就很有可能不会得到我们想要的结果。
完整测试代码
#include <iostream>
class CompanyA {
public:
static void Print() {
std::cout << "I am A!" << std::endl;
}
};
class CompanyB {
public:
static void Print() {
std::cout << "I am B!" << std::endl;
}
};
template<typename Company>
class Sender {
public:
void Print() {
std::cout << "Base MessageSender!" << std::endl;
Company::Print();
}
};
template<typename T>
class MessageSender : public Sender<T> {
public:
//using Sender<T>::Print;
void SenderPrint() {
this->Print();
//Sender<T>::Print();
}
};
int main() {
MessageSender<CompanyA> s;
s.SenderPrint();
return 0;
}