Проблемный дизайн модификации/доступа к информации производного класса с использованием базового объекта

Моя проблема заключается в следующем:

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» из основного метода (в этом примере) базовый объект не знает, какие переменные находятся внутри структуры производного класса .

Могу ли я как-то это осознать? Что я могу получить различные свойства каждого производного объекта, но используя объект базового класса?


person user1555151    schedule 26.07.2012    source источник
comment
Вы можете установить базовые отношения между двумя PropertyStruct с разными именами.   -  person iammilind    schedule 26.07.2012


Ответы (3)


Как уже упоминалось, здесь есть способы достичь ваших целей, но в конечном итоге вы обнаружите, что пишете код, подобный следующему:

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

Если нецелесообразно помещать требуемую обработку в производные классы (т. е. если это приведет к нежелательным обязанностям), вы можете рассмотреть Шаблон посетителя как способ расширить функциональность вашей иерархии.

person Andrew Durward    schedule 26.07.2012

Поскольку функции шаблона не могут быть виртуальными, вы можете использовать иерархию своих свойств. Это только один путь, других способов нет. Для получения элементов производных свойств вы должны использовать виртуальные функции получения.

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(); }
};
person ForEveR    schedule 26.07.2012
comment
@Code-Guru Нет других способов достичь цели, которые хотят OP без получения. - person ForEveR; 26.07.2012

Для этого вы можете использовать класс шаблона:

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;
}
person Kevin MOLCARD    schedule 26.07.2012