[英]Class derived from a class with multiple inheritance in C++: the derived class is trying to call the root base class constructor
[英]C++ multiple inheritance and access specifiers: inherit from a base class and its derived
这是我遇到的意外问题。 我正在编写一个GUI应用程序,并且使用GUI库中的两个类:Model类和View类。 Model的内容由View类呈现到屏幕上。 在某个时候,我决定派生Model类,因为我需要扩展功能。 该库的类是派生的,我发现了许多示例。 这很容易并且完美地工作了。
现在有一个问题:Model类提供了直接编辑模型数据的方法。 我不希望这些方法公开,因为我写了包装器,而这些包装器必须是唯一的编辑方法。 我确实需要继承,因为派生的MyModel覆盖了Model类的许多虚拟方法。 所以我在想该怎么办。 以下是所有详细信息的摘要:
因此,我想公开MyModel的迭代接口,以便可以将其传递给View对象,但隐藏Model提供的编辑接口。
我想到的解决方案:
解决方案1:无法避免继承,因为我必须使用虚方法,但是解决方案本身不必使用继承:我可以为MyModel类编写包装器,该类提供对封装的MyModel的const引用的访问。对象,并为MyModel的编辑机制提供包装。 由于所有的包装器,这可能很丑陋,但它避免了多重继承和访问说明符的混乱。
解决方案2:让 MyModel继承Model。 没有多重继承。 现在转到MyModel.hpp中的MyModel的类定义,并在protected
ir private
下编写所有Model的编辑方法的方法声明,以便将它们隐藏。 效果很好,但是维护方面存在一个小问题:如果在库的未来版本中,Model接口发生了变化,例如添加了新的编辑方法,则我们必须将其作为私有/手动添加到MyModel类中。受保护的方法。 当然,我可以跟踪库的更改,或者至少可以转到其在线API参考并浏览Model类参考页面,以确保没有任何更改,或者在必要时在生产/稳定版本的CD之前更新我的代码。我的申请被释放。
解决方案3:使用多重继承,然后我不知道会发生什么。 是否安全? 行为编译器是否依赖。 这就是想法:MyModel从Model和basicModel继承:从BasicModel的public
继承(用于迭代接口),从Model的protected/private
继承(以隐藏模型的编辑接口)。
笔记:
注1 :我的高级编辑机制使用 Model的低级编辑方法。
注2 :虚拟方法MyModel覆盖了它们,其中一些方法是由BasicModel定义的(因此也由Model继承),而某些方法在BasicModel中不存在,而是由Model定义的(例如,与拖放相关的方法)。
注3:我使用的GUI库是gtkmm ,是GTK +的C ++绑定,而我正在谈论的类是Gtk :: TreeModel,Gtk :: TreeStore,Gtk :: TreeView和我自己的MyModel类,它们是从Gtk派生的:: TreeStore。 我忽略了这些名称,因为该问题是一个通用的OO规划问题,但是我在这里提到的是真正的课程,以便熟悉它们的人可以更轻松地理解问题。
我不确定这里最好的设计。 无疑,解决方案3是维护成本最低的解决方案。 实际上是零,因为继承访问说明符只是自动完成所有工作。 问题是,解决方案3是否总是按预期工作,例如对于迭代方法,编译器将其公开(由于从BasicModel继承公共继承)还是私有(由于从Model继承私有,继承自BasicModel)。 我从来没有像这样使用多重继承...
伪代码
库或多或少是这样工作的:
namespace GUI
{
class BasicModel
{
public:
/* iteration interface for observing the model */
iterator get_iter();
// but no data here, it's just an interface which calls protected virtual methods
// which are implemented by deriving classes, e.g. Model
protected:
virtual iterator get_iter_vfunc() = 0;
virtual void handle_signal();
};
class Model : public BasicModel
{
/* inherits public iteration interface*/
/* implements observation virtual methods from BasicModel*/
virtual iterator get_iter_vfunc() { /*...*/ }
/* has private data structures for the model data */
std::vector<Row> data;
/* has public editing interface, e.g. insert_row(), erase(), append()
/* has protected drag-n-drop related virtual methods*/
virtual void handle_drop();
};
}
我的代码:
class MyModel : public GUI::Model
{
/* implements virtual methods from BasicModel, e.g. default signal handlers*/
virtual void handle_signal() { /*...*/ }
/* implements drag-n-drop virtual methods from Model*/
virtual void handle_drop() { *...* }
/* inherits public iteration interface*/
/* inherits public editing interface (***which I want to hide***)
/* implements its own editing mechanism*/
void high_level_edit (int param);
};
尝试GCC
我尝试了以下代码,在关闭警告的情况下进行了编译(否则,GCC抱怨):
#include <iostream>
class Base
{
public:
void func ()
{
std::cout << "Base::func() called" << std::endl;
func_vfunc ();
}
protected:
virtual void func_vfunc ()
{
std::cout << "Base::func_vfunc() called" << std::endl;
}
};
class Derived : public Base
{
protected:
virtual void func_vfunc ()
{
std::cout << "Derived::func_vfunc() called" << std::endl;
}
};
class MyClass : public Base, private Derived
{
};
int main (int argc, char* argv[])
{
Base base;
Derived derived;
MyClass myclass;
base.func ();
derived.func ();
myclass.func ();
return 0;
}
由于某些原因,GCC坚持认为myclass.func()
的调用是模棱两可的,但是由于私有继承,我们认为其中一个func()
应该是私有的,所以我不明白为什么它不能编译。 最重要的是,假设这不是一个错误,但只是我不了解事情是如何工作的-建议的多重继承解决方案是不可能的。 如果我没记错的话,解决此问题的唯一方法是虚拟继承,但是我不能使用它,因为我使用的类是库类,并且它们不使用虚拟继承。 而且即使那样,由于我同时使用私有继承和公共继承,所以它可能无法解决问题,仍然是一个模棱两可的电话。
编辑:我试图使Derived和MyClass实际上从Base派生,它完全解决了这个问题。 但就我而言,我无法更改库类,因此这不是一种选择。
如果我正确理解了您的问题,则可能应该混合使用继承(MyModel源自BaseModel)和组合(MyModel包含Model的私有实例)。
然后在MyModel中使用您自己的基本虚拟方法的实现,对于那些您不想重新实现的方法,只需使其成为相应的Model方法的代理即可。
无论如何,恕我直言,您应该避免多重继承。 否则,随着时间的流逝,它会变得很毛茸茸。
编辑:现在我可以看到代码,我再给它一个镜头。
您需要做的是重新实现MyModelImpl类(来自Model的派生类)中需要的内容,该类将隐藏在代理类MyModel(BaseModel的派生类)中。 我的第一个想法非常相似,只是我不了解您需要重新实现Model的某些部分。
类似于以下内容:
class MyModel : public BaseModel {
public:
void high_level_edit(int param) { m_impl.high_level_edit(param); }
protected:
virtual iterator get_iter_vfunc() { return m_impl.get_iter_vfunc(); }
virtual void handle_signal() { m_impl.handle_signal(); }
private:
class MyModelImpl : public Model {
public:
void high_level_edit(int param);
// reimplement whatever you need (methods present in BaseModel,
// you need to call them from MyModel proxies)
virtual iterator get_iter_vfunc() { /*...*/ }
protected:
// reimplement whatever you need (methods present only in Model,
// you don't need to call them from MyModel proxies)
virtual void handle_drop();
};
MyModelImpl m_impl;
};
我相信应该可以正常工作,因为BaseModel中没有实际状态(数据),除非再次误解了 ...
你可以做类似的事情
class MyModel : protected Model
{
public:
using Model::iterator;
//it will make iterator public in MyModel
}
如果我正确地理解了这种情况,并且假设Model没有从可迭代的类中秘密继承,那么我想这一定是这种情况。 如果我说些蠢话,请原谅我。 我不是一个非常有经验的编码员。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.