模板基类与正确的派生类函数调用--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是否存在于基类。

解决办法

但是凡事都有解决办法,这里的话主要是有三种解决方式。

  1. 利用this指针
template<typename T>
class MessageSender : public Sender<T> {
public:
    void AugMentSenderPrint() {
	// doing other augment stuff
        this->Print();
    }
};
  1. 利用using声明
template<typename T>
class MessageSender : public Sender<T> {
public:
    using Sender<T>::print;
    void SenderPrint() {
        Print();
    }
};
  1. 静态绑定
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;
}
posted @ 2022-10-07 12:01  相隔半世  阅读(32)  评论(0编辑  收藏  举报