2017-02-13 15 views
3

私には問題があることを教えてあげてください。私は、デジタルデバイスを制御する一連のクラスを設計しています。このデバイスは、2つの動作モードで動作します。第1のモードでは、特定の操作セットを実行することができ、第2のモードでは、別の操作セットを実行することができる。私はまた、実行時にデバイスのモードを変更することができますので、必要に応じて2つのモードを入れ替えることができます。モードとは無関係に、デバイスは同じレジスタセットを使用します。同じ名前のメンバーを持つ基本クラスからのC++多重継承

私はこの問題を各モードごとに1つの基本クラスで解決しようと考えていました。したがって、最初の操作セットが必要な場合はモード1のオブジェクトを、2番目の操作セットを必要とする場合はモード2のオブジェクトが必要です。そして、私はこれらの2つの基本クラスからクラスを派生することができたので、すべての操作を実行するオブジェクトを持つことができます。

私の設計の問題は、2つの基本クラスに共通の機能と同じレジスタへの参照があることです。私はメンバーの継承を防ぐことができないので、派生クラスに重複があります。私はスコープ演算子でアクセスする複製を選択できることを知っていますが、私はまだこれを悪い設計と考えています。

私の質問です:この問題を解決するための慣用的な方法はありますか?

これを解決する方法が簡単でない場合は、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はoperation2と共通のすべてのデータメンバを有します。

+0

なぜすべての操作を実行するオブジェクトが必要ですか? – immibis

+0

何を試しましたか? – Raindrop7

+0

仮想継承を見てください。 –

答えて

1

私はのは、あなたのデータとメンバ関数operation2を備え、Commonを言わせて、共通の基底クラスでmode1mode2の共通部分を置くところ。次に、仮想継承と一緒に、同じデータに対して、必要に応じて同時に2つのビューを設定することができます。

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(); 
} 

デバイスのユーザの観点から、あなたが使用しているモードだかは重要ではありません。とにかく、要望どおりにいつでも動的に変更することができ、その時点から新しいモードでデバイスが動作するようになります。
継承に優先してコンポジションを優先すると、競合する名前の問題が解決されます。外部クラスから内部状態へのすべての委譲は、残りの処理を行います。

ステート間でメソッドを共有する場合、基本クラスにメソッドを配置することはできません。

A、わずかに異なるバージョンを使用すると、補数の間でもデータを共有することができます:

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内に置くと、無視することができます異なるモードで作業しています。

関連する問題