在C++中为抽象类模板创建接口

bis*_*ash 22 c++ inheritance templates pointers interface

我有如下代码.我有一个抽象模板类Foo和两个子类(Foo1和Foo2),它们派生自模板的实例化.我希望在我的程序中使用指向Foo1或Foo2类型的对象的指针,因此我创建了一个接口IFoo.

我的问题是我不确定如何在界面中包含functionB,因为它依赖于模板实例化.甚至可以通过界面使functionB可访问,还是我尝试不可能?

非常感谢您的帮助.

class IFoo {
    public:
        virtual functionA()=0;

};

template<class T>
class Foo : public IFoo{
    public:
        functionA(){ do something; };
        functionB(T arg){ do something; };
};

class Foo1 : public Foo<int>{
...
};

class Foo2 : public Foo<double>{
...
};
Run Code Online (Sandbox Code Playgroud)

Mat*_* M. 17

你实际上在尝试不可能的事.

事情的非常心脏很简单:virtualtemplate不拌匀.

  • template是关于编译时代码生成.您可以将其视为某种类型感知宏+一些用于元编程的技巧.
  • virtual 是关于运行时决定,这需要一些工作.

virtual通常使用虚拟表来实现(想象一下列出方法的表).需要在编译时知道方法的数量,并在基类中定义.

但是,根据您的要求,我们需要一个无限大小的虚拟表,其中包含我们尚未看到的类型的方法,并且只会在未来几年内定义......遗憾的是不可能.

如果可能的话?

嗯,这没有意义.当我打电话,会发生什么Foo2int?它并不意味着它!因此它打破了Foo2实现所有方法的原则IFoo.

所以,如果你说出真正的问题会更好,这样我们可以在设计层面而不是技术层面帮助你:)


Igo*_*aka 8

最简单的方法是使您的界面模板化.

template <class T>
class IFoo {
    public:
        virtual void functionA()=0;
        virtual void functionB(T arg){ do something; };
};

template<class T>
class Foo : public IFoo<T>{
    public:
        void functionA(){ do something; };
        void functionB(T arg){ do something; };
};
Run Code Online (Sandbox Code Playgroud)

  • 这意味着我无法创建IFoo类型的指针并让它们指向Foo1或Foo2的实例化. (5认同)
  • 这是正确的,这是一个根本问题.`functionB`采用的参数类型取决于实例化的模板类型,**必须在编译时知道. (3认同)

Nor*_*ame 5

由于 functionB 的参数类型必须提前知道,因此您只有一个选择:使其成为可以容纳所有可能的参数的类型。这有时被称为“顶级类型”,并且 boost 库的类型any非常接近顶级类型的功能。这是可行的:

#include <boost/any.hpp>
#include <iostream>
using namespace boost;

class IFoo {
    public:
    virtual void functionA()=0;
    virtual void functionB(any arg)=0; //<-can hold almost everything
};

template<class T>
class Foo : public IFoo{
    public:
        void functionA(){  };
        void real_functionB(T arg)
        {
         std::cout << arg << std::endl;
        };
        // call the real functionB with the actual value in arg
        // if there is no T in arg, an exception is thrown!

        virtual void functionB(any arg)
        {
            real_functionB(any_cast<T>(arg));
        }
};

int main()
{
    Foo<int> f_int;
    IFoo &if_int=f_int;

    if_int.functionB(10);

    Foo<double> f_double;
    IFoo &if_double=f_double;
if_int.functionB(10.0);

}
Run Code Online (Sandbox Code Playgroud)

不幸的是,any_cast不知道通常的转换。例如any_cast<double>(any(123))抛出异常,因为它甚至没有尝试将整数 123 转换为双精度。如果不关心转换,因为无论如何都不可能复制所有转换。因此存在一些限制,但如有必要,可以找到解决方法。


Kar*_*tan 0

我不认为你能得到你想要的。如果您要实现您的建议,请考虑一下:如果您有一个指向IFoo实例的指针并且您调用functionB(),您应该给它什么类型的参数?根本问题是Foo1::functionBFoo2::functionB具有不同的签名并执行不同的操作。