C++ C++;通过继承实现的基于组件的架构是否被认为是良好的实践?

C++ C++;通过继承实现的基于组件的架构是否被认为是良好的实践?,c++,oop,inheritance,interface,components,C++,Oop,Inheritance,Interface,Components,当我有一个异构对象的容器时,我正在实现一个体系结构,这些对象可能有或没有一些公共方法属性。我需要遍历它们,应用一些函数,更新一些成员,并通过各种接口调用一些方法 我提出了一种基于继承的“标准”体系结构: #include <vector> #include <memory> #include <iostream> using namespace std; struct Base { virtual ~Base() {} }; struct Pos

当我有一个异构对象的容器时,我正在实现一个体系结构,这些对象可能有或没有一些公共方法属性。我需要遍历它们,应用一些函数,更新一些成员,并通过各种接口调用一些方法

我提出了一种基于继承的“标准”体系结构:

#include <vector>
#include <memory>
#include <iostream>

using namespace std;

struct Base {
    virtual ~Base() {}
};

struct PositionInterface {
    int x = 0;
    int y = 0;
    virtual ~PositionInterface() {}
};
struct DrawInterface {
    void draw() { cout << "Here i am" << endl; }
    virtual ~DrawInterface() {}
};
struct ChargeInterface {
    int charge = 100;
    virtual ~ChargeInterface() {}
};
struct LifeInterface {
    int life = 100;
    virtual ~LifeInterface() {}
};

struct A: public Base,
          public LifeInterface, public PositionInterface {};
struct B: public Base,
          public DrawInterface, public PositionInterface, public ChargeInterface {};

int main() {
    std::vector<std::shared_ptr<Base>> vec;
    vec.push_back(make_shared<A>());
    vec.push_back(make_shared<B>());

    for (auto & el : vec) {
        auto p = dynamic_cast<PositionInterface *>(el.get());
        if (p) {
            p->x += 10;
            p->y -= 10;
        }
    }
    // ..other stuff
    for (auto & el : vec) {
        auto l = dynamic_cast<LifeInterface *>(el.get());
        if (l) {
            l->life -= 100;
        }
    }
    // ..other stuff
    for (auto & el : vec) {
        auto d = dynamic_cast<DrawInterface *>(el.get());
        if (d) {
            d->draw();
        }
    }
}
但是,我怎样才能循环通过
Base
objects
dynamic\u cast
ing的向量到达正确的界面呢


您看到这种体系结构(除了RTTI和公共变量:-)有什么缺点吗?

RTTI的主要缺点是使用它,因此使其不可能是一件好事

可能使用空指针、接口指针返回函数或类似于
boost::optional
的类型

例如:

class Base
{
public:
    virtual LifeInterface* life() { return 0; }
    virtual PositionInterface* position() { return 0; }
};

class A: public Base {
public:
    LifeInterface* life() { return &l; }
private:
    LifeInterface l;
};

// ...

for (auto & el : vec) {
    auto l = el.life();
    if (l) {
        l->life -= 100;
    }
}
“但是,我怎样才能循环通过基本对象的向量动态_投射到正确的界面?”

我建议使用真正的抽象接口,例如:

struct Base {
    virtual ~Base() {}
};

struct PositionInterface {
    virtual int x() const = 0;
    virtual void x(int value) = 0;
    virtual int y() const = 0;
    virtual void y(int value) = 0;
    virtual ~PositionInterface() {}
};

struct DrawInterface {
    virtual void draw() const = 0;
    virtual ~DrawInterface() {}
};

struct ChargeInterface {
    virtual int charge() const = 0;
    virtual ~ChargeInterface() {}
};

struct LifeInterface {
    virtual int life() const {};
    virtual ~LifeInterface() {}
};

可以用作mixin的基本实现类

class PositionBase : public PositionInterface {
public:
    virtual int x() const { return x_; }
    virtual void x(int value) { x_ = value; }
    virtual int y() const { return y_; }
    virtual void y(int value) { y_ = value; }
    virtual ~PositionBase() {}

protected:
    PositionBase() {}
    int x_;
    int y_;
};

class ChargeBase : public ChargeInterface {
public:
    virtual int charge() const { return charge_; }
    virtual ~ChargeInterface() {}

protected:
    ChargeBase(int charge) : charge_(charge) {}
    const int charge_;
};

class LifeBase : public LifeInterface {
public:
    virtual int life() const { return life_; }
    virtual ~LifeBase() {}

protected:
    LifeBase(int life) : life_(life) {}
    const int life_;
};
您的实现如下所示

struct A 
: public virtual Base
, public LifeBase
, public PositionBase {
    A() : Base(), LifeBase(100), PositionBase() {}
};

struct B 
: public virtual Base
, public DrawInterface
, public PositionBase
, public ChargeBase {
    B() : Base(), PositionBase(), ChargeBase(100)
    virtual void draw() const {
        // Must implement draw()
    }
};
  • 不要使用公共成员变量,因为您无法从继承的类中真正控制这些变量。如上图所示,使用虚拟getter/setter函数
  • 要检查是否支持正确的界面,请使用
    dynamic\u cast
    。要对这些对象执行操作,请提供简单的模板化函数,例如:

  • 模板作废图(常数和项目){
    DrawInterface*drawableItem=dyndraw();
    }
    //项目不可绘制,忽略或引发异常
    }
    
    我不提供任何公共变量,只提供用于接口声明的纯虚拟getter/setter/operations。
    struct A 
    : public virtual Base
    , public LifeBase
    , public PositionBase {
        A() : Base(), LifeBase(100), PositionBase() {}
    };
    
    struct B 
    : public virtual Base
    , public DrawInterface
    , public PositionBase
    , public ChargeBase {
        B() : Base(), PositionBase(), ChargeBase(100)
        virtual void draw() const {
            // Must implement draw()
        }
    };
    
    template<class T> void draw(const T& item) {
        DrawInterface* drawableItem = dyn<mic_cast<DrawInterface*>(&item);
        if(drawableItem) {
            drawableItem->draw();
        }
        // Item isn't drawable, ignore or throw exception
    }