简体   繁体   English

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

[英]C++ multiple inheritance from base classes with members with same name

Let me tell you the problem I have. 让我告诉你我的问题。 I'm designing a set of classes to control a digital device. 我正在设计一组控制数字设备的类。 This device can work in two modes of operation. 该设备可以在两种操作模式下工作。 In the first mode it can perform a specific set of operations, and in the second mode it can perform another set of operations (with possibly some common operations between the two). 在第一模式中,它可以执行一组特定的操作,而在第二模式中,它可以执行另一组操作(在两者之间可能有一些共同的操作)。 I can also change the mode of the device on the run, so I can swap between the two modes if necessary. 我也可以在运行时更改设备的模式,因此如有必要,我可以在两种模式之间切换。 Independently of the mode, the device use the same set of registers. 与模式无关,设备使用相同的寄存器集。

I was thinking in solve this problem with one base class for each mode, so I can have objects of mode 1 when I need the first set of operations and objects of mode 2 when I need the second set of operations. 我正在考虑用每个模式的一个基类来解决这个问题,所以当我需要第一组操作和模式2的对象时,当我需要第二组操作时,我可以拥有模式1的对象。 Then I could derive a class from these two base classes, so I can have objects that perform all the operations. 然后我可以从这两个基类派生一个类,所以我可以拥有执行所有操作的对象。

The problem with my design is that the two base classes have some common functions and references to the same registers. 我的设计的问题是两个基类有一些共同的功能和对相同寄存器的引用。 Since I can't prevent inheritance of members I would have duplicates in the derived class. 由于我无法阻止成员的继承,因此我会在派生类中重复。 I know I can choose which duplicate to access with the scope operator, but I still think this a bad design. 我知道我可以选择使用范围运算符访问哪些副本,但我仍然认为这是一个糟糕的设计。

So my question is: is there an idiomatic way of solve this problem? 所以我的问题是:是否有一种解决这个问题的惯用方法?

If there isn't a right or easy way of solving this, I'm thinking about design 3 hierarchically independently classes. 如果没有正确或简单的方法来解决这个问题,我正在考虑设计3层次独立的类。 I would have some duplicate code, but that is not a big problem, right? 我会有一些重复的代码,但这不是一个大问题,对吧?

Code below (simplified) for illustration: 以下代码(简化)用于说明:

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

Note modes 1 and 2 have operation2 and all the data members in common. 注意模式1和2具有operation2和所有数据成员的共同点。

The state design pattern looks like a good candidate for your case. 状态设计模式看起来像是一个很好的候选人。
As a minimal, working example: 作为一个最小的工作示例:

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

From the point of view of the user of the device, it doesn't matter what's the mode you are using. 从设备用户的角度来看,您使用的模式无关紧要。 Anyway, as requested, you can dynamically change it whenever you want and your device will start to work with the new mode from that point on. 无论如何,根据要求,您可以随时动态更改它,并且您的设备将从此时开始使用新模式。
Preferring composition over inheritance solves the issue due the conflicting names. 由于名称冲突,优先考虑组合而不是继承解决了这个问题。 Delegating everything from the outer class to the inner state does the rest. 委托从外部类到内部状态的所有内容完成其余的工作。

Note that, if you want to share methods between states, nothing prevents you from putting them in the base class. 请注意,如果要在状态之间共享方法,则不会阻止您将它们放在基类中。

A slightly different version helps you sharing also data between the twos: 略有不同的版本可以帮助您在两者之间共享数据:

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

All those parameters that are unique for a specific mode can be part of the class definition or put within Data and ignored if you are working in a different mode. 对于特定模式而言唯一的所有参数可以是类定义的一部分,也可以放在Data ,如果您在其他模式下工作则忽略。

I'd put the common parts of mode1 and mode2 in a common base class, let's say Common , comprising then your data and member function operation2 . 我将mode1mode2的公共部分放在一个公共基类中,比如说Common ,然后包含你的数据和成员函数operation2 Then, together with virtual inheritance, you can have two views on the same data, even at the same time if needed. 然后,与虚拟继承一起,您可以在同一数据上拥有两个视图,即使在需要时也可以同时使用。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C ++多重继承,其基类派生自同一个类 - C++ multiple inheritance with base classes deriving from the same class C ++从相同的基本模板歧义继承 - C++ Multiple inheritance from same base template ambiguity C++ 从多个具有相同虚函数名称的基类继承 - C++ inherit from multiple base classes with the same virtual function name 使用多个继承和模板访问基类的成员 - Access the members of base classes with multiple inheritance and templates C ++多重继承,与派生对象中基类的地址混淆 - C++ multiple inheritance, confused with addresses of base classes in derived object 有关C ++中多重继承,虚拟基类和对象大小的问题 - Question on multiple inheritance, virtual base classes, and object size in C++ C ++调用基类的虚拟运算符==具有多重继承 - c++ invoke base classes' virtual operator== with multiple inheritance 从基类继承私有成员到派生类C ++ - Inheriting private members from base class to derived classes c++ 基类为一个方法共享相同名称时的多重继承C ++,有一些限制吗? - Multiple inheritance C++ when bases classes share the same name for a method, is there some limit? 多个超类中的多个 Inheritance、C++ 和相同的方法签名 - Multiple Inheritance, C++ and Same Method Signature in Multiple Super Classes
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM