我通常使用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。
任何帮助表示感谢。
答案 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
,而无需实现IDoSomething1
和IDoSomething2
。第二种方法MethodExpectsDosomething2
将无法编译,因为Foo
没有DoSomething2
方法。
在C#中,此类构造是不可能的,并强制您拥有IDoSomething1
和IDoSomething2
接口,并将其指定为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::DoSomething
和IWhatever::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所需要的东西。