Nic*_*ton 12 c++ multiple-inheritance
这是我们理想的继承层次结构:
class Foobar;
class FoobarClient : Foobar;
class FoobarServer : Foobar;
class WindowsFoobar : Foobar;
class UnixFoobar : Foobar;
class WindowsFoobarClient : WindowsFoobar, FoobarClient;
class WindowsFoobarServer : WindowsFoobar, FoobarServer;
class UnixFoobarClient : UnixFoobar, FoobarClient;
class UnixFoobarServer : UnixFoobar, FoobarServer;
Run Code Online (Sandbox Code Playgroud)
这是因为我们的继承层次结构会尝试从Foobar
两次继承,因此,编译器会抱怨任何成员的模糊引用Foobar
.
请允许我解释为什么我想要这么复杂的模型.这是因为我们希望有来自同一个变量访问WindowsFoobar
,UnixFoobar
,FoobarClient
,和FoobarServer
.这不会是一个问题,只是我想使用上面任意组合的多重继承,这样我就可以在任何平台上使用服务器/客户端功能,并在客户端或服务器上使用平台功能.
我不禁觉得这是多重继承的一个常见问题...我是从完全错误的角度来解决这个问题吗?
另外,考虑到我们可以使用它#ifdef
来解决这个问题,但是,这会产生非常难看的代码,例如:
CFoobar::CFoobar()
#if SYSAPI_WIN32
: m_someData(1234)
#endif
{
}
Run Code Online (Sandbox Code Playgroud)
...哎!
对于那些想要更多地了解这个问题的人,我真的建议浏览相应的邮件列表线程.在第3篇文章开始变得有趣.还有一个相关的代码提交,您可以在此处查看有问题的真实代码.
Kor*_*icz 18
它会工作,虽然你得到两个基Foobar
类副本.要获得单个副本,您需要使用虚拟继承.在这里阅读多重继承.
class Foobar;
class FoobarClient : virtual public Foobar;
class FoobarServer : virtual public Foobar;
class WindowsFoobar : virtual public Foobar;
class UnixFoobar : virtual public Foobar;
Run Code Online (Sandbox Code Playgroud)
但是,存在许多与多重继承相关的问题.如果你真的想要展示模型,为什么不在施工时制作FoobarClient
并FoobarServer
参考Foobar
,然后Foobar& FoobarClient/Server::getFoobar
呢?
组合通常是多重继承的一种方式.现在举个例子:
class WindowsFoobarClient : public WindowsFoobar
{
FoobarClient client;
public:
WindowsFoobarClient() : client( this ) {}
FoobarClient& getClient() { return client }
}
Run Code Online (Sandbox Code Playgroud)
但是在构造函数中使用它必须小心.
你在这里直接得到的是C++的虚拟继承功能.你在这里的是维护噩梦.这可能不是一个巨大的惊喜,因为像H. Sutter这样的着名作家已经反对这种继承的使用已经有一段时间了.但这来自对此类代码的直接体验.避免深度继承链.非常害怕protected
关键字 - 它的使用非常有限.这种设计很快就会失控 - 跟踪受保护变量的访问模式,从较低级别的类继承链变得困难,代码部分的责任变得模糊等等,以及那些一年查看代码的人从现在开始会恨你:)
你是C++,你应该对模板友好.使用template-argument-is-a-base-class模式,您不需要任何多重继承或冗余实现.它看起来像这样:
class Foobar {};
template <typename Base> class UnixFoobarAspect : public Base {};
template <typename Base> class WindowsFoobarAspect : public Base {};
template <typename Base> class FoobarClientAspect : public Base {};
template <typename Base> class FoobarServerAspect : public Base {};
typedef UnixFoobarAspect<FoobarClientAspect<Foobar>/*this whitespace not needed in C++0x*/> UnixFoobarClient;
typedef WindowsFoobarAspect<FoobarClientAspect<Foobar> > WindowsFoobarClient;
typedef UnixFoobarAspect<FoobarServerAspect<Foobar> > UnixFoobarServer;
typedef WindowsFoobarAspect<FoobarServerAspect<Foobar> > WindowsFoobarServer;
Run Code Online (Sandbox Code Playgroud)
您还可以考虑使用奇怪的重复模板模式,而不是在基类需要调用在一个专用变体中实现的函数时,声明抽象函数以避免虚函数调用.
归档时间: |
|
查看次数: |
8234 次 |
最近记录: |