我怀疑答案是“不”或“你做错了”,但是:
是否可以实现接口类型行为而不使用C ++中的继承(11,如果重要的话)?
我有几个不同的结构,
struct Foo
{
float A;
void Bind()
{ .... }
};
struct Bar
{
float B;
void Bind()
{
}
};
......和其他人
这些是通过将这些结构的数组传递给另一个进程的方法来操作的,并且它们必须非常紧密地包装。如果我使用继承,创建一个实现::Bind()
方法的基类,那么后代类不仅有他们的数据,还有一个VMT,它占用了非常稀缺资源的一大部分。其他方法需要对这些不同类型进行操作,但并不真正关心数据成员或::Bind()
方法的细节,这两种方法在类型之间存在很大差异。
在C#中(或者,我怀疑是java),我会做类似的事情:
interface ICommon
{
void Bind();
}
struct Foo : ICommon
{
void Bind() { .... };
};
struct Bar : ICommon
{
void Bind() { ..... }
}
我可以使用模板:
template<typename T>
void Bind(T &item)
{
item.Bind();
}
但是这引入了一些不太理想的约束(即模板需要在头部而不是cpp等中声明)。我知道有些hacks可以让你在cpp文件中放一个模板方法,但是它们有点乱,我宁愿避免它。
这可能是“有你的蛋糕,也吃它”的要求。
(请注意,这并不是其他C ++接口问题的重复,因为我试图避免使用经常推荐的使用多重继承的解决方案。)
答案 0 :(得分:1)
是否可以实现接口类型行为而不使用C ++中的继承(11,如果重要的话)?
是。封装是继承的可行替代方案。
您使用接口来定义某些行为,然后返回接口(接口仍然是继承的,但不是由您的主类继承)。
示例:
class IBinder {
virtual void Bind() = 0;
};
class Foo: public WhateverBaseClass {
struct Binder: public IBinder { virtual void Bind() override {} };
Binder b;
public:
IBinder& getBinder() { return b; }
};
客户代码:
Foo f;
f.getBinder().Bind();
答案 1 :(得分:1)
如果您真的不想使用模板或继承,可以使用重载的自由函数:
void Bind(Foo& foo) {}
void Bind(Bar& bar) {}
int main() {
Foo foo;
Bar bar;
Bind(foo);
Bind(bar);
}
当然,任何需要对这两种类型进行操作的函数都必须过载或模板化。
答案 2 :(得分:1)
使用模板参数可以获得几乎相同的结果:
template <typename TRAIT>
class ICommon
{
TRAIT t;
public: void Bind()
{
t.Bind();
}
}
class FooTrait
{
public: void Bind() { .... };
};
class BarTrait
{
public void Bind() { ..... }
}
typedef ICommon<FooTrait> Foo;
typedef ICommon<BarTrait> Bar;
template <typename T>
void call_bind(ICommon<T> x)
{
x.Bind();
}
int main()
{
Foo f; Bar b;
call_bind(f);
call_bind(b);
}
答案 3 :(得分:0)
Java的接口只是一种淡化邪恶,邪恶,交叉的心脏,我们不会做到这一点,多重继承。没什么。
对于您的问题,如果您想获得一堆共享&#34;界面的对象,&#34;做得很自然:他们属于到接口的类,即从它派生。可以创建一个(指向)这些对象的数组,甚至可以对对象本身进行一些关注(但除非绝对必要,否则我不会去那里,切掉某些东西的危险太大了。)
Re:&#34;仅在标题中使用模板&#34;:说谁?只包含头文件(可能在几个不同的源文件中),以避免反复编写相同的声明(和内联定义)。如果你需要模板或类,或者只是在一个源文件中,noboby将强制你为此创建一个标题。