C++从具有相同名称的成员的基类继承多重继承

问题描述:

让我告诉你我遇到的问题。我正在设计一组控制数字设备的类。该设备可以在两种操作模式下工作。在第一种模式下,它可以执行一组特定的操作,而在第二种模式下,它可以执行另一组操作(两者之间可能有一些共同的操作)。我还可以在运行中更改设备的模式,以便在必要时可以在两种模式之间切换。独立于该模式,器件使用相同的一组寄存器。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

看看虚拟继承。 –

我把的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

状态设计模式看起来很适合您的情况。
作为最小的,工作示例:

#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投入,而忽视那些参数以不同的模式工作。