【问题标题】:Problematic design modifiying/accessing information of a derived class using the base object有问题的设计使用基对象修改/访问派生类的信息
【发布时间】:2012-07-25 05:56:25
【问题描述】:

我的问题如下:

int main()
{
    Base* derivedobject = new Derived1();
    derivedobject->GetProperties()-> ???

return 0;
}

//********************
// BaseClass.h
//********************
struct PropertyStruct
{
    int x;
};

class Base
{
public:
    Base();
    ~Base();

    virtual PropertyStruct GetProperties() = 0;

private:
};

//********************
// DerivedClass1.h
//********************
struct PropertyStruct
{
    int y;
};

class Derived1 : public Base
{
public:
    Derived1();
    ~Derived1();

    PropertyStruct GetProperties() { return myOwnDifferentProperties; };

private:

};

//********************
// DerivedClass2.h
//********************
struct PropertyStruct
{
    float z;
};

class Derived2 : public Base
{
public:
    Derived2();
    ~Derived2();

    PropertyStruct GetProperties() { return myOwnDifferentProperties };

private:

};

如果我这样做,我会得到一个错误,说 PropertyStruct 是一个重新定义。如果我在派生类中使用命名空间或重命名结构,则会收到一个错误,告诉我返回类型与 Base 定义的不同。 如果我将虚函数返回类型定义为它编译的指针,尽管从主方法(在本例中)访问函数“GetProperties”时的下一个问题是基对象不知道派生类的结构内有哪些变量.

有什么方法可以让我意识到这一点吗? 我可以使用基类对象获取每个派生对象的不同属性吗?

【问题讨论】:

  • 可以在两个不同名字的PropertyStruct之间建立base-derived关系。

标签: c++ inheritance polymorphism derived


【解决方案1】:

正如其他人所提到的,这里有多种方法可以实现您的目标,但最终您会发现自己编写如下代码:

    Base * object = ...;

    if object is Derived1 then
      get Property1 and do something with it
    else if object is Derived2 then
      get Property2 and do something with it

这是面向对象编程中的反模式。您已经有一个类层次结构来表示各种派生类型之间的差异。与其从对象中提取数据并在外部进行处理,不如考虑向基类添加一个虚函数并让派生类进行处理。

class Base
{
public:

    virtual void DoSomething() = 0;
};

class Derived1 : Base
{
public:

    void DoSomething()
    {
        // use myOwnDifferentProperties as necessary
    }

private:

    PropertyStruct myOwnDifferentProperties;
};

如果将所需的处理放在派生类中是不合适的(即,如果它会引入不必要的责任),那么您可能需要考虑将Visitor Pattern 作为扩展层次结构功能的一种方式。

【讨论】:

    【解决方案2】:

    您可以使用模板类来做到这一点:

    struct PropertyStruct1 {
        float f;
    };
    
    struct PropertyStruct2 {
        int i;
    };
    
    template<class T>
    class A{
    public:
        T GetProperties() {return mProps;}
    
    private:
        T mProps;   
    };
    
    int main (int argc, const char * argv[]) {
    
        A<PropertyStruct1> a1;
        int f = a1.GetProperties().f;
        A<PropertyStruct2> a2;
        int i = a2.GetProperties().i;
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      由于模板函数不能是虚拟的,您可以使用属性的层次结构。这只是一种方式,没有其他方式。对于派生属性的获取元素,您应该使用虚拟 getter 函数。

      struct BaseProp
      {
          virtual ~BaseProp() { }
          virtual boost::any getProperty() const = 0;
      };
      
      struct PropertyStruct : BaseProp
      {
          boost::any getProperty() const { return x; }
      private:
          int x;
      };
      
      struct PropertyStruct2 : BaseProp
      {
          boost::any getProperty() const { return y; }
      private:
          float y;
      };
      
      class Base
      {
      public:
          virtual std::shared_ptr<BaseProp> GetProperties() const = 0;
          virtual ~Base() { }
      }
      
      class Derived
      {
      public:
          std::shared_ptr<BaseProp> GetProperties() const { return new PropertyStruct(); }
      };
      
      class Derived2
      {
      public:
          std::shared_ptr<BaseProp> GetProperties() const { return new PropertyStruct2(); }
      };
      

      【讨论】:

      • @Code-Guru 没有其他方法可以实现目标,需要 OP 而无需派生。
      猜你喜欢
      • 1970-01-01
      • 2015-05-23
      • 1970-01-01
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多