2011-04-15 46 views
0

我正在为我的容器类派生一个基类,以便我可以维护一致的接口。目前,它看起来是这样的:具有不同数据类型的纯虚拟方法

template <typename Datatype> 
class BaseClass 
{ 
    public: 
    virtual Datatype Foo() = 0; 
    virtual Datatype Bar() = 0; 
}; 

template <typename Datatype> 
class DerivedClass: public BaseClass<Datatype> 
{ 
    public: 

    virtual Datatype Foo() 
    { 
    } 

    virtual Datatype Bar() 
    { 
    } 
}; 

不过,我的一些派生类,Foo()Bar()可能需要具有彼此不同的返回类型。如果没有基类中每个不同返回类型的模板参数,我怎么能给派生类一些空间来改变这种事情呢?

编辑:

派生类使用的类型是可能完全不同的和不变的。实际上,派生类不保证除方法名称之外有任何共同点。

+3

“派生类不保证有任何形式的方法名称以外的共同点” - 那么这是一个“一致的接口”,然后呢?如果我有一个'BaseClass * p',如果某些子类返回int并且其他返回'std :: string',我将如何以及为什么要调用'p-> Foo()'?尽管如此,你也许可以抛出Boost.Variant或Boost.Any。 – 2011-04-15 12:18:57

+0

@Steve这个想法是我可以创建一个不关心数据类型的非朋友,非成员函数。例如,说一个将元素插入容器的函数。 – Maxpm 2011-04-15 12:36:45

+1

不幸的是编译器需要“知道”返回类型来调用一个函数,即使你不使用结果。这是为了允许调用者提供堆栈空间来写结果的调用约定(并且据我所知,几乎所有事情都是这样做的)。因此,您可以在返回类型无关的情况下使用模板代码(因为编译器会在模板实例化时计算出来,但程序员不在意),但动态多态性不会以这种方式工作 - 调用虚拟函数需要返回类型对于所有覆盖都是相同的。 – 2011-04-15 12:43:10

回答

1

不可能以return不同的数据类型。唯一的办法是制定方法template并且这是受限制的,因为virtual方法不能是模板。

1

如果返回类型是co-variant,它们可以改变,或者你可以写一些类型的转换函数,并且有类似real_bar或类似的东西。

+0

+1协变返回类型。 – ildjarn 2011-04-15 12:06:01

+0

这些类型可能完全不同,并且没有链接到任何类层次结构中。例如,一个派生类可能会为'Foo()'返回一个'int',而对于'Bar()'则返回一个'string',而另一个类则为两者返回'vector's等。 – Maxpm 2011-04-15 12:09:29

+0

@Maxpm:你知道吗所有潜在派生类的返回类型都在前面? – ildjarn 2011-04-15 12:20:59

1

traits可能会有所帮助。 C++ Templates - The Complete Guide这本书提供了一个例子,在标题为特性和策略类的一章中对此进行了说明。它有一个使用累加器返回不同类型的示例。

编辑:我可以看到AProgrammer已经给出的例子已经

6

提供将专门在你需要不同的结果的情况下,一种品质。

template <typename Datatype> 
struct BaseTraits 
{ 
    typedef Datatype FooResult; 
    typedef Datatype BarResult; 
}; 

template <typename Datatype, typename Traits = BaseTraits<Datatype> > 
class BaseClass 
{ 
    public: 
    virtual Traits::FooResult Foo() = 0; 
    virtual Traits::BarResult Bar() = 0; 
}; 
3

如果你知道潜在的类型数量的时间提前可以延长你已通过添加其他类型的基类模板得到了什么?

template <typename FOO_TYPE,typename BAR_TYPE> 
class BaseClass 
{  
public:  
    virtual FOO_TYPE Foo() = 0;  
    virtual BAR_TYPE Bar() = 0; 
}; 

template <typename FOO_TYPE,typename BAR_TYPE> 
class DerivedClass: public BaseClass<FOO_TYPE,BAR_TYPE> 
{  
public:  
    virtual FOO_TYPE Foo() { }  
    virtual BAR_TYPE Bar() { } 
}; 

这能拿出来的如果你有几种类型的话,可以快速交付。

1
#include <iostream> 
#include <typeinfo> 

using namespace std; 

template <typename T, typename R = T> 
class base 
{ 
    public: 
    virtual R foo() 
    { 
     cout << "foo(): data type = " << typeid(T).name() << endl; return R(); 
    } 

    virtual R bar() 
    { 
     cout << "bar(): return type = " << typeid(R).name() << endl; return R(); 
    } 
}; 

int main() 
{ 
    base<int> b; 
    base<int, long> b1; 

    b.foo(); b.bar(); 
    b1.foo(); b1.bar(); 

    cout << typeid(b).name() << endl; 
    cout << typeid(b1).name() << endl; 

    return 0; 
} 

上述程序返回以下:

随着g++

$ ./rettypetemplate 
foo(): data type = i 
bar(): return type = i 
foo(): data type = i 
bar(): return type = l 
4baseIiiE 
4baseIilE 

与Visual Studio 2005 cl.exe

C:\Program Files\Microsoft Visual Studio 8\VC>rettypetemplate.exe 
foo(): data type = int 
bar(): return type = int 
foo(): data type = int 
bar(): return type = long 
class base<int,int> 
class base<int,long> 

虽然这个示例显示了如何做到这一点, AProgrammer给出的答案显示了一个很好的方法它使用特质。上面的例子适用于基本数据类型,但不适用于用户定义的类型。为了处理用户定义的类型,性状是要走的路。请参阅Jossutis的"The C++ Template" book或“Modern C++ design”以了解更多关于性状的信息。

相关问题