双继承和多态。如何从一个基类中拥有两个独立的成员?

Posted

技术标签:

【中文标题】双继承和多态。如何从一个基类中拥有两个独立的成员?【英文标题】:Double inheritance and polymorphism. How to have two separated members from one base class? 【发布时间】:2017-12-09 14:57:48 【问题描述】:

我需要对从 BaseA 继承的对象使用 do_something 的多态性,但我的 D 对象应该有两个名为 enabled 的独立成员。我的意思是 D::changeEnabled() 应该改变 SecondBaseB::BaseA::enabled = 0SecondBaseC::BaseA::enabled = 0 并且这两个成员应该是分开的(不同的)。是否可以具有多态性而不使用虚拟继承?没有virtual public BaseA 我有模棱两可的错误。但是对于虚拟继承,我只有一个BaseA::enabled

//
// main.cpp
//
#include <iostream>
#include "D.h";

void do_something(BaseA& o) 
    o.changeEnabled();


int main() 
  SecondBaseB b;
  SecondBaseC c;
    D d;
  do_something(b);
  do_something(c);
    do_something(d);
    std::cout « "Hello, World!" « std::endl;
    return 0;


//
// BaseA.h
//
class BaseA 
protected:
    bool enabled;
public:
    BaseA();
    virtual void changeEnabled() = 0;
;

//
// BaseA.cpp
//
#include "BaseA.h"

BaseA::BaseA() : enabled(true) 



//
// SecondBaseB.h
//
class SecondBaseB : virtual public BaseA
public:
    virtual void changeEnabled();
;

//
// SecondBaseB.cpp
//
#include "SecondBaseB.h"

void SecondBaseB::changeEnabled() 
    enabled = !enabled;


//
// SecondBaseC.h
//
#include "BaseA.h"

class SecondBaseC : virtual public BaseA 
public:
    virtual void changeEnabled();
;

//
// SecondBaseC.cpp
//
#include "SecondBaseC.h"

void SecondBaseC::changeEnabled() 
    enabled = !enabled;


//
// D.h
//
#include "SecondBaseB.h"
#include "SecondBaseC.h"

class D : public SecondBaseB, public SecondBaseC
public:
    virtual void changeEnabled();
;

换个说法。我有以下场景:带有engine 成员的基础抽象类Car。我创建了从 Car 继承的 DieselCarElectricCar。然后我想创建 HybridCar,它将继承自 DieselCarElectricCar 并有两个不同的 engines。使用虚拟继承只有一个引擎。如果不使用virtual,我将无法完成以下操作:

void testDrive(Car* c) 
c->drive();
c->drive();


HybridCar h;
ElectricCar e;

testDrive(&h);
testDrive(&e)

【问题讨论】:

模板和std::enable_if() 是处理此类情况的绝佳工具。 如果有两个不同的enabled 成员,你希望do_something(d) 做什么? 使用virtual 基类表示您只需要一个该类型的基对象。既然你想要两个,不要使用虚拟继承。 D 必须明白有两个基础并采取相应的行动。 【参考方案1】:

谈论您的 Car 场景,要获得关于 Car 子类的多个信息,这些子类不止一个 Engine,可以使用 Composite 重构代码模式,以这种方式:

汽车拥有发动机 Engine 是一个接口或抽象类,其作用类似于 组件 Leaf 是 Engine 的具体子类,其含义类似于 ElectricEngineDieselEngine 等...李> PowerUnit 的作用类似于 Composite,因此它拥有对某些 Engine 的引用

然后Car的每个具体子类的每个构造函数都初始化属性

Engine* engine;

在抽象类Car中以正确的方式声明。 例如,

 ElectricCar()
     //other members
     engine=new ElectricEngine();
 

 DieselCar()
    //other members
    engine=new DieselCar();
 

 HybridCar()
   //hybrid car is composed by an electric and diesel engine
   engine=new PowerUnit(Engine* engines);
 

如果抽象类看起来像

 class Engine
    private bool enabled;
    public:
       virtual Engine* getEngine(int number=0) return this;
       virtual final bool isEnabled()return this->enabled;
       virtual final void setEnabled(bool value) this->enabled=value;
    

getEngine() 方法必须在子类 PowerUnit 的真实函数中实现。

class PowerUnit
     private:
        Engine*[] engines;
     public:
       PowerUnit()
         engines[0]=new ElectricCar();
         engines[1]=new DieselCar();
       
       getEngine(int number) return engines[number];
   

最后,如果客户 (Car) 想要检查混合动力汽车哪个引擎处于活动状态(或两者都处于活动状态),它可以使用指针 engine,如以下方式检查第一个引擎是否处于活动状态:

engine->getEngines(0)->isEnabled;

【讨论】:

以上是关于双继承和多态。如何从一个基类中拥有两个独立的成员?的主要内容,如果未能解决你的问题,请参考以下文章

5继承与派生6-虚基类

C++ | 类继承

继承和多态

多态虚函数表底层实现多重继承的问题及处理

java继承和多态的学习

在继承的类中启动线程