这段代码:

template <typename T>
struct A
{
     T t;

     void DoSomething()
     {
          t.SomeFunction();
     }
};

struct B
{
};

A<B> a;

只要我从未调用a.DoSomething(),就可以轻松编译而不会有任何提示。

但是,如果我将DoSomething定义为虚函数,则会出现编译错误,指出B没有声明SomeFunction。我有点明白为什么会发生这种情况(DoSomething现在应该在vtable中有一个条目),但是我不禁感到它并不是真正的义务。再加上它很烂。

有什么办法可以克服这个问题?

编辑2:好的。我希望这次有道理:
假设我正在进行侵入式引用计数,因此所有实体都必须继承自基类Object。我如何也可以支持基本类型?我可以定义:
template <typename T>
class Primitive : public Object
{
    T value;
public:
    Primitive(const T &value=T());

    operator T() const;

    Primitive<T> &operator =(const T &value);
    Primitive<T> &operator +=(const T &value);
    Primitive<T> &operator %=(const T &value);

    // And so on...
};

所以我可以使用Primitive<int>Primitive<char> ...
但是Primitive<float>呢?这似乎是一个问题,因为浮点数没有%=运算符。但实际上并非如此,因为我永远不会在operator %=上调用Primitive<float>
这是模板的故意功能之一。

如果由于某种原因,我将operator %=定义为虚拟的。或者,如果我要从dll中预导出Primitive<float>以避免链接错误,即使我从未在operator %=上调用Primitive<float>,编译器也会提示。如果只是在operator %=的vtable中为Primitive<float>填充一个虚拟值(会引发异常?),一切都会很好。

最佳答案

将虚函数放入可选的基类中...

struct Jumper
{
    virtual void Jump =0;
};

struct Crawler
{
    virtual void Crawl() =0;
};

struct JumperCrawler:
    public Jumper,
    public Crawler
{
};

template<typename T, typename Methods>
class ICanBoostJumpingAndCrawling :
    public Methods
{
    T t;
};

现在,您可以将ICanBoostJumpingAndCrawling与作为Methods模板参数提供的Jumper,Crawler或JumperCrawler一起使用;意识到需要从中派生它,以便可以在子类中实现Jumping和/或Crawling。

仅供引用,这使“ICanBoostJumpingAndCrawling”这个名称完全具有误导性,因为它可能会或可能不会这样做;这意味着应将其重命名为“Booster”之类的名称。

关于c++ - 模板类+虚函数=必须实现?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1489744/

10-11 17:43