我有一个简单的低级容器类,由更高级别的文件类使用。基本上,在将最终版本保存到实际文件之前,文件类使用容器在本地存储修改。因此,某些方法直接从容器类传递到文件类。 (例如,Resize()
。)
我刚刚在文件类中定义方法来调用它们的容器类变体。例如:
void FileClass::Foo()
{
ContainerMember.Foo();
}
但是,这种情况越来越令人讨厌。有更好的方法吗?
这是一个简化的例子:
class MyContainer
{
// ...
public:
void Foo()
{
// This function directly handles the object's
// member variables.
}
}
class MyClass
{
MyContainer Member;
public:
void Foo()
{
Member.Foo();
// This seems to be pointless re-implementation, and it's
// inconvenient to keep MyContainer's methods and MyClass's
// wrappers for those methods synchronized.
}
}
答案 0 :(得分:7)
那么,为什么不直接从MyContainer
继承并通过using
声明公开那些你想要转发的函数呢?这被称为“根据 MyClass
实施MyContainer
。
class MyContainer
{
public:
void Foo()
{
// This function directly handles the object's
// member variables.
}
void Bar(){
// ...
}
}
class MyClass : private MyContainer
{
public:
using MyContainer::Foo;
// would hide MyContainer::Bar
void Bar(){
// ...
MyContainer::Bar();
// ...
}
}
现在,“外部”可以直接拨打Foo
,而Bar
只能在MyClass
内访问。如果你现在创建一个具有相同名称的函数,它会隐藏基函数,你可以像这样包装基函数。当然,您现在需要完全限定对基本函数的调用,否则您将进行无休止的递归。
此外,如果你想允许(非多态)子类MyClass
,这是一个罕见的地方,受保护的继承实际上是有用的:
class MyClass : protected MyContainer{
// all stays the same, subclasses are also allowed to call the MyContainer functions
};
如果您的MyClass
没有虚拟析构函数,则为非多态。
答案 1 :(得分:1)
是的,维护这样的代理类非常烦人。您的IDE可能有一些工具可以使它更容易一些。或者您也可以下载IDE插件。
但除非您需要支持许多功能和覆盖以及模板,否则通常不会非常困难。
我通常把它们写成:
void Foo() { return Member.Foo(); }
int Bar(int x) { return Member.Bar(x); }
它很好而且对称。 C ++允许您在void函数中返回void值,因为这样可以使模板更好地工作。但是你可以使用相同的东西来使其他代码更漂亮。
答案 2 :(得分:1)
那是delegation inheritance而且我不知道C ++提供了任何帮助它的机制。
答案 3 :(得分:1)
考虑一下你的案例中有意义的事情 - MyClass和MyContainer之间的组合(拥有)或继承(是a)关系。
如果你不想再拥有这样的代码,你几乎只限于实现继承(MyContainer作为基类/抽象基类)。但是,您必须确保在您的应用程序中实际上这是有意义的,并且您不是纯粹为了实现而继承(实现的继承很糟糕)。
如果有疑问,你所拥有的可能很好。
编辑:我更习惯于在Java / C#中思考并且忽略了这样一个事实:C ++在他的答案中使用了更大的继承灵活性。在这种情况下,这感觉就像是一个很好的解决方案。答案 4 :(得分:0)
您需要编写大量代码的此功能实际上是必需的功能。 C ++是一种冗长的语言,如果你试图避免用c ++编写代码,你的设计将永远不会很好。
但这个问题的真正问题在于班级没有行为。它只是一个什么都不做的包装。除了传递数据外,每个班级都需要做一些事情。
关键是每个班级都有正确的界面。此要求使得必须编写转发功能。每个成员函数的主要目的是分发所有数据成员所需的工作。如果您只有一个数据成员,并且您还没有确定该类应该做什么,那么您所拥有的只是转发功能。一旦你添加了更多的成员对象并决定了该类应该做什么,那么你的转发功能将变为更合理的东西。
有助于此的一件事是让你的课程变小。如果接口很小,每个代理类只有很小的接口,接口不会经常改变。