[英]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.