2017-02-13 155 views
3

讓我告訴你我遇到的問題。我正在設計一組控制數字設備的類。該設備可以在兩種操作模式下工作。在第一種模式下,它可以執行一組特定的操作,而在第二種模式下,它可以執行另一組操作(兩者之間可能有一些共同的操作)。我還可以在運行中更改設備的模式,以便在必要時可以在兩種模式之間切換。獨立於該模式,器件使用相同的一組寄存器。C++從具有相同名稱的成員的基類繼承多重繼承

我在考慮用每個模式的一個基類來解決這個問題,所以當我需要第二組操作時需要模式2的第一組操作和對象時,我可以擁有模式1的對象。然後我可以從這兩個基類中派生一個類,這樣我就可以擁有執行所有操作的對象。

我的設計的問題是兩個基類有一些共同的功能和引用相同的寄存器。既然我不能阻止成員的繼承,我會在派生類中重複。我知道我可以選擇使用範圍操作符訪問哪個副本,但我仍然認爲這是一個糟糕的設計。

所以我的問題是:有沒有解決這個問題的地道方式?

如果沒有解決這個問題的正確或簡單的方法,我在考慮設計3層次獨立的類。我會有一些重複的代碼,但這不是一個大問題,對吧?爲了說明下面(簡化的)

代碼:

class mode1 
{ 
protected: 
    volatile uint8_t& reg1; 
    volatile uint8_t& reg2; 
    uint8_t data; 
public: 
    virtual void operation1() final { // do something } 
    virtual void operation2() final { // do something } 
    virtual void operation3() final { // do something } 
}; 


class mode2 
{ 
protected: 
    volatile uint8_t& reg1; 
    volatile uint8_t& reg2; 
    uint8_t data; 
public: 
    virtual void operation4() final { // do something } 
    virtual void operation2() final { // do something } 
    virtual void operation5() final { // do something } 
}; 


class mode1and2 : public mode1, public mode2 
{ 
public: 
    void operation6() { // do something } 
    void operation7() { // do something } 
}; 

注模式1和2具有操作2和在共同所有數據成員。

+0

爲什麼你想要一個執行所有操作的對象? – immibis

+0

你嘗試了什麼? – Raindrop7

+0

看看虛擬繼承。 –

回答

1

我把的mode1mode2公用部分公共基類,比方說Common,包括那麼你的數據和成員函數operation2。然後,與虛擬繼承一起,您可以在同一數據上擁有兩個視圖,即使在需要的同時也是如此。

class common { 
    friend class mode1; 
    friend class mode2; 
protected: 
    volatile uint8_t& reg1; 
    volatile uint8_t& reg2; 
    uint8_t data; 

public: 
    virtual void operation2() final { // do something 
    }; 

}; 

class mode1 : public virtual common 
{ 
public: 
    virtual void operation1() final { // do something 
    }; 
    virtual void operation3() final { // do something } 
    }; 
}; 

class mode2 : public virtual common 
{ 
public: 
    virtual void operation4() final { // do something 
    } 
    virtual void operation5() final { // do something 
    } 
}; 


class mode1and2 : public mode1, public mode2 
{ 
public: 
    void operation6() { // do something } 
    }; 
    void operation7() { // do something } 
    }; 
}; 
+0

我正在閱讀關於虛擬繼承。看起來這正是我正在尋找的。謝謝,斯蒂芬。 – rrd

1

狀態設計模式看起來很適合您的情況。
作爲最小的,工作示例:

#include<memory> 
#include<iostream> 

struct Behavior { 
    virtual void f() = 0; 
    virtual void g() = 0; 
}; 

struct NullBehavior: Behavior { 
    void f() override {} 
    void g() override {} 
}; 

struct Mode1: Behavior { 
    void f() override { std::cout << "mode 1 - f" << std::endl; } 
    void g() override { std::cout << "mode 1 - g" << std::endl; } 
}; 

struct Mode2: Behavior { 
    void f() override { std::cout << "mode 2 - f" << std::endl; } 
    void g() override { std::cout << "mode 2 - g" << std::endl; } 
}; 

struct Device { 
    template<typename B> 
    void set() { behavior = std::unique_ptr<Behavior>{new B}; } 

    void f() { behavior->f(); } 
    void g() { behavior->g(); } 

private: 
    std::unique_ptr<Behavior> behavior{new NullBehavior}; 
}; 

int main() { 
    Device device; 
    device.f(); 
    device.g(); 

    device.set<Mode1>(); 
    device.f(); 
    device.g(); 

    device.set<Mode2>(); 
    device.f(); 
    device.g(); 
} 

從視設備的用戶的角度來看,它並不重要什麼是您所使用的模式。無論如何,根據要求,您可以隨時動態更改,並且您的設備將從此時開始使用新模式。
比繼承更喜歡構圖解決了由於名稱衝突導致的問題。其餘部分從外部類委派給內部狀態。

請注意,如果您想在狀態之間共享方法,則不會阻止您將它們放入基類中。

一個稍微不同的版本可以幫助你也是三三兩兩之間共享數據:

struct Data { 
    volatile uint8_t& reg1; 
    volatile uint8_t& reg2; 
    uint8_t data; 
}; 

struct Behavior { 
    virtual void f(Data &) = 0; 
    virtual void g(Data &) = 0; 
}; 

struct NullBehavior: Behavior { 
    void f(Data &) override {} 
    void g(Data &) override {} 
}; 

struct Mode1: Behavior { 
    void f(Data &) override { /* ... */ } 
    void g(Data &) override { /* ... */ } 
}; 

struct Mode2: Behavior { 
    void f(Data &) override { /* ... */ } 
    void g(Data &) override { /* ... */ } 
}; 

struct Device { 
    template<typename B> 
    void set() { behavior = std::unique_ptr<Behavior>{new B}; } 

    void f() { behavior->f(data); } 
    void g() { behavior->g(data); } 

private: 
    Data data{}; 
    std::unique_ptr<Behavior> behavior{new NullBehavior}; 
}; 

所有,如果你是在一個特定的模式可以是類定義的一部分,唯一的或內Data投入,而忽視那些參數以不同的模式工作。