gpt4 book ai didi

c++ - C++多重继承和访问说明符:从基类及其派生继承

转载 作者:太空宇宙 更新时间:2023-11-04 11:59:05 28 4
gpt4 key购买 nike

这是我遇到的意外问题。我正在编写一个GUI应用程序,并且使用GUI库中的两个类:Model类和View类。 Model的内容由View类呈现到屏幕上。在某个时候,我决定派生Model类,因为我需要扩展功能。该库的类是派生的,我发现了许多示例。这很容易并且完美地工作了。

现在有一个问题:Model类提供了直接编辑模型数据的方法。我不希望这些方法公开,因为我写了包装器,而这些包装器必须是唯一的编辑方法。我确实需要继承,因为派生的MyModel覆盖了Model类的许多虚拟方法。所以我在想该怎么办。以下是所有详细信息的摘要:

  • 有一个BasicModel类,该类提供用于遍历模型数据
  • 的方法
  • 有一个Model类,该类继承BasicModel,并通过提供用于编辑数据的方法(我认为BaseModel是抽象的并且没有数据,并且Model定义内部数据结构并实现BasicModel提供的迭代接口(interface))来扩展它。
  • 有一个MyModel类,它继承了Model。它覆盖了许多虚拟方法,具有扩展的编辑机制,并希望隐藏Model
  • 提供的低级编辑方法。
  • 有一个View类,该类存储指向BasicModel对象的指针。因此,View仅使用迭代界面,甚至不知道任何编辑界面。

  • 因此,我希望公开MyModel的迭代接口(interface),以便可以将其传递给View对象,但隐藏Model提供的编辑接口(interface)。

    我想到的解决方案:

    解决方案1:无法避免继承,因为我必须使用虚方法,但是解决方案本身不必使用继承:我可以为MyModel类编写包装器,该类提供对封装的MyModel的const引用的访问。对象,并为MyModel的编辑机制提供包装。由于所有的包装器,这可能很丑陋,但可以避免混乱多个继承和访问说明符。

    解决方案2:让MyModel继承Model。没有多重继承。现在转到MyModel.hpp中的MyModel的类定义,并在 protectedprivate下编写所有Model的编辑方法的方法声明,以便将它们隐藏。这很好用,但是维护方面有一个小问题:如果在库的 future 版本中,模型接口(interface)会发生变化,例如添加了新的编辑方法,我们必须将其作为私有(private)/ protected 方法手动添加到MyModel类中。当然,我可以跟踪库的更改,或者至少可以转到其在线API参考并浏览Model类参考页面,以确保没有任何更改,或者在必要时在生产/稳定版本的CD之前更新我的代码。我的申请被释放。

    解决方案3:使用多重继承,然后我不知道会发生什么。是否安全?行为编译器是否相关。这是一个主意:MyModel从Model和basicModel继承:从BasicModel的 public继承(用于迭代接口(interface))和从Model的 protected/private继承(以隐藏Model的编辑接口(interface))。

    注意:

    注1:我的高级编辑机制使用Model的低级编辑方法。

    注意2:虚拟方法MyModel覆盖,其中一些由BasicModel定义(因此也由Model继承),而某些在BasicModel中不存在并且由Model定义(例如与拖放相关的方法)。

    注意3:我使用的GUI库是 gtkmm GTK + 的C++绑定(bind),而我正在谈论的类是Gtk::TreeModel,Gtk::TreeStore,Gtk::TreeView和我自己的MyModel类,它源自Gtk::TreeStore。我忽略了这些名称,因为该问题是一个通用的OO规划问题,但是我在这里提到的是真正的类(class),以便熟悉它们的人可以更轻松地理解问题。

    我不确定这里最好的设计是什么。无疑,解决方案3是维护成本最低的解决方案。实际上是零,因为继承访问说明符会自动完成所有工作。问题是,解决方案3是否总是按预期工作,例如对于迭代方法,编译器会将其设置为公开(由于从BasicModel继承到公共(public))还是私有(private)(由于从Model继承自BasicModel的私有(private))。我从来没有像这样使用多重继承...

    伪代码

    库或多或少是这样工作的:
    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()的调用含糊不清,但由于私有(private)继承,我们认为其中之一是私有(private)的 func(),因此我不明白为什么它无法编译。最重要的是,假设这不是一个错误,但只是我不了解事情是如何工作的-建议的多重继承解决方案是不可能的。如果我没记错的话,解决此问题的唯一方法是虚拟继承,但是我不能使用它,因为我使用的类是库类,并且它们不使用虚拟继承。而且即使那样,由于我同时使用私有(private)继承和公共(public)继承,所以它可能无法解决问题,仍然是一个模棱两可的选择。

    编辑:我试图使Derived和MyClass实际上从Base派生,它完全解决了这个问题。但就我而言,我无法更改库类,因此这不是一种选择。

    最佳答案

    如果我正确理解了您的问题,则可能应该混合使用继承(MyModel源自BaseModel)和组合(MyModel包含Model的私有(private)实例)。

    然后在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中没有实际状态(数据),除非再次误解了...

    关于c++ - C++多重继承和访问说明符:从基类及其派生继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14909071/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com