首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >继承模板方法

继承模板方法
EN

Stack Overflow用户
提问于 2011-07-15 13:51:14
回答 3查看 10.5K关注 0票数 9

我有一个类似于下面的类:

代码语言:javascript
复制
class SomeClass
{
    public:
        template<typename... Args>
        void doSomething(Args && ... args);

        //... other methods etc.
};

然而,我真正想要的是拥有两种不同的SomeClass。理想情况下,我可以从一个公共接口派生出SomeOtherClass,但是我需要一个不同的doSomething实现,并且模板化的方法不能是虚拟的。我可以创建一个模板化的类,但是每个接受其中一个(有很多)的方法本身都必须是模板,等等。

我所能想到的最好的方法是在基类中实现这两种类型的doSomething,并让该方法调用一个虚方法来确定在运行时使用哪一个。

有没有更好的解决方案?

进一步解释

我有很多类似下面的方法:

代码语言:javascript
复制
void foo(SomeClass * obj);

foo调用obj->doSomething,这一切都很好,但是我后来意识到我需要一种不同的SomeClass,但希望它与这些相同的方法一起工作,例如:

代码语言:javascript
复制
class SomeClass
{
    public:
        // This won't work
        template<typename... Args>
        virtual void doSomething(Args && ... args) = 0;

        // ... other common methods
};

class TheFirstType
{
    public:
        template<typename... Args>
        void doSomething(Args && ... args);

        // ... other specific methods
};

class TheSecondType
{
    public:
        template<typename... Args>
        void doSomething(Args && ... args);

        // ... other specific methods
};

如果它是合法的,上面的方法将是理想的,但是虚拟方法不能被模板化。到目前为止,我只在基类中定义了doSomething,但是TheFirstTypeTheSecondType的实现都由一个if语句分隔,该语句检查实例的实际类型:

代码语言:javascript
复制
template<typename... Args>
void SomeClass::doSomething(Args && ... args)
{
    if (this->type() == FIRST_TYPE) {
        // ... the implementation that should rightfully be part of TheFirstType
    } else if (this->type() == SECOND_TYPE) {
        // ... the implementation that should be part of TheSecondType
    }
}

然而,这看起来很混乱,所以我想知道是否有更好的方法。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-07-16 11:33:31

我认为@stijn的答案是正确的;您有一个理想的CRTP案例。你可以选择根据这一点改变你的逻辑。

代码语言:javascript
复制
template<class T>
class SomeClass
{
public:
  template<typename... Args>
  void doSomething(Args && ... args)
  {
    static_cast<T*>(this)->doSomething(...);
  }
  //other method can be virtual
  virtual void foo ()
  {
    doSomething(...);
    // ... other code;
  }
};

现在只需将这些class继承到您的其他子类:

代码语言:javascript
复制
class TheFirstType : SomeClass<TheFirstType>
{
public:
  template<typename... Args>
  void doSomething(Args && ... args) { ... }

  virtual void foo ()
  {
  }
};   // do same for TheSecondType.

你的任务完成了。

票数 6
EN

Stack Overflow用户

发布于 2011-07-15 16:18:23

我的猜测是你在追求CRTP (尽管我不能确定,正如iammilind在评论中指出的那样):

代码语言:javascript
复制
template< class Parent >
class SomeClassBase : public Parent
{
public:
  //common methods go here
};

class SomeClass : public SomeClassBase< SomeClass >
{
public:
  template<typename... Args>
  void doSomething(Args && ... args);
};

class SomeOtherClass : public SomeClassBase< SomeOtherClass >
{
public:
  template<typename... Args>
  void doSomething(Args && ... args);
};
票数 3
EN

Stack Overflow用户

发布于 2018-06-01 06:24:41

在这种情况下,在包装器类SomeClass中使用宏函数可能会有所帮助。宏的好处是文本替换。通常,我们不能在C++中将一个带有所有参数的函数作为一个对象传递(至少在C++11之前,在那之后,我不确定)。然而,使用宏,我们几乎可以传递任何类型的文本。这里增加的好处是,它将为每个具有这种模板-虚拟冲突的函数删除if/else的重复代码。

我们可以按如下方式设置宏:

代码语言:javascript
复制
#define CLASS_SELECT(func) \
do { \
    if (this->type() == FIRST_TYPE) { \
        theFirstType.func; \
    } else if (this->type() == SECOND_TYPE) { \
        theSecondType.func; \
    } \
} while (0)

如果您不熟悉do while封装,可以使用look here。该类将使用宏,如下所示:

代码语言:javascript
复制
class SomeClass
{
    TheFirstType theFirstType;
    TheSecondType theSecondType;
public:
    template<typename... Args>
    void doSomething(Args && ... args)
    {
        CLASS_SELECT(doSomething (&args...) );
    }
};

在上面的示例中,我实例化了SomeClass中的专门化对象。我不确定这是否是您喜欢的设计,如果不是,我会考虑在宏中使用静态getter函数或类似函数。

无论如何,我承认我的解决方案可能并不理想,但这是迄今为止我得到的最好的解决方案(我在我的代码中遇到了与您相同的问题)。我承认在其他答案中引用的CRTP非常酷,尽管它不符合我的需求(必须在参数中指定模板也不适合我,特别是在运行时)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6703199

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档