用C ++实现接口

时间:2012-01-03 16:50:25

标签: c# c++ interface multiple-inheritance porting

我通常使用C#编程,但我正在尝试做一些C ++,并且在尝试用C ++实现接口方面有点挣扎。

在C#中我会做这样的事情:

class Base<T>
{
    public void DoSomething(T value)
    {
        // Do something here
    }
}

interface IDoubleDoSomething
{
    void DoSomething(double value);
}

class Foo : Base<double>, IDoubleDoSomething
{
}

在C ++中我实现了这样:

template <class T>
class Base
{
public:
    virtual void DoSomething(T value)
    {
        // Do something here
    }
};

class IDoubleDoSomething
{
public:
    virtual void DoSomething(double value) = 0;
};

class Foo : public Base<double>, public IDoubleDoSomething
{
};

问题是我无法实例化Foo,因为它是抽象的(不实现DoSomething)。我意识到我可以实现DoSomething并在Base上调用该方法,但我希望有更好的方法来实现这一点。我有其他类从base继承不同的数据类型,我有其他类继承自不使用Base的IDoubleDoSomething。

任何帮助表示感谢。

6 个答案:

答案 0 :(得分:2)

考虑以下c ++代码

class Foo
{
public:
    void DoSomething1(){}
};

template<typename t>
void MethodExpectsDosomething1( t f )
{
    f.DoSomething1();
}

template<typename t>
void MethodExpectsDosomething2( t f )
{
    f.DoSomething2();
}

int main()
{
    Foo f;
    MethodExpectsDosomething1<Foo>( f );

    MethodExpectsDosomething2<Foo>( f );

    return 0;
}

在C ++中,您可以使用Foo,而无需实现IDoSomething1IDoSomething2。第二种方法MethodExpectsDosomething2将无法编译,因为Foo没有DoSomething2方法。

在C#中,此类构造是不可能的,并强制您拥有IDoSomething1IDoSomething2接口,并将其指定为type constraint

所以也许您需要查看代码并查看是否需要此类接口?

答案 1 :(得分:2)

在C ++中,必须始终在派生类中重写纯虚函数;他们不能继承其他基类的覆盖。如果你需要动态多态,我认为在调用Foo函数的Base中编写函数没有任何明智的选择。请注意,Base函数不需要是虚拟的。

根据您使用这些类的方式(特别是在编译时是否知道接口的每个实例的实际类型),您可以使用静态多态将您的特定实现类注入其用户模板参数;例如:

// No explicit interface specification with static polymorphism
class Foo : public Base<double>
{
    // Inherits DoSomething(double)
};

// Template can used with any class that impelements a 
// "DoSomething" function that can accept a double.
template <class DoubleDoSomething>
void DoSomethingWithDouble(DoubleDoSomething & interface, double value)
{
    interface.DoSomething(value);
}

// This particular specialisation uses a "Foo" object.
Foo foo;
DoSomethingWithDouble(foo, 42);

答案 2 :(得分:2)

问题是,Base::DoSomethingIWhatever::DoSomething是两个不相关的函数(即使这里没有任何纯虚函数,你也无法调用DoSomething一个Foo对象,无论如何)。 Base需要继承IWhatever才能实现此目的。

那就是说,问问自己是否真的需要这个。使用模板(和概念,有点像接口 - 参见Boost.ConceptCheck)的通用编程通常是C ++中比运行时子类型多态性更好的解决方案。

答案 3 :(得分:2)

您可以将第二个模板参数传递给Base,即要实现的接口:

template <typename T, class Interface>
class Base : public Interface { ... };

class Foo : public Base<double, IDoubleDoSomething> { ... };

对于额外奖励积分,您可以对IDoubleDoSomething进行模仿(例如IDoSomething<double>),或者使用traits类将类型T映射到相关界面。

答案 4 :(得分:1)

正如其他人所说,基类中的两个函数是无关的(尽管具有相同的名称和参数类型),因为它们没有公共基类。如果你想让它们相关,你需要给它们一个共同的基类。

此外,通常,如果您希望多重继承正常工作,则需要将非私有基类声明为virtual。否则,如果你有共同的基类(正如你经常需要这种代码风格),那么就会发生不好的事情。

因此,您可以使您的示例如下工作:

template <class T>
class IDoSomething {
public:
    virtual void DoSomething(T value) = 0;
};

template <class T>
class Base : public virtual IDoSomething<T>
{
public:
    virtual void DoSomething(T value)
    {
        // Do something here
    }
};

class IDoubleDoSomething : public virtual IDoSomething<double>
{
};

class Foo : public virtual Base<double>, public virtual IDoubleDoSomething
{
};

答案 5 :(得分:-1)

如果其他所有内容都有序,这应该可行。

class Foo : public Base<double>
{
};

在你的原始代码中,Foo将有2个void DoSomething(double value)方法(1个是抽象的)。 那将是一个Base部分和一个IDoubleDoSomething部分。 Foo :: Base和Foo :: IDoubleDoSomething。 您可以通过临时给予和实现IDoubleDoSomething.DoSomething()来尝试。

但是,因为Foo已经“是一个”基地“你没有IDoubleDoSomething所需要的东西。