使用基对象修改/访问派生类的信息的有问题的设计

Problematic design modifiying/accessing information of a derived class using the base object

本文关键字:信息 有问题 派生 访问 对象 修改      更新时间:2023-10-16

我的问题如下:

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"时,基对象不知道派生类的结构中有哪些变量。

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

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

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

如果不适合将所需的处理放在派生类中(即,如果它会引入不需要的责任),那么您可能需要将访问者模式视为扩展层次结构功能的一种方式。

由于模板函数不能是虚拟的,所以可以使用属性的层次结构。这只是一种方式,没有其他方式。对于派生Properties的get元素,应该使用虚拟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(); }
};

您可以使用模板类来实现这一点:

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