2015-12-30 3 views
1

Я хочу реализовать некоторую иерархию классов с полиморфизмом, и я не могу заставить его работать. У меня есть две проблемы:Производный класс с дополнительными частными атрибутами

  1. производный класс имеет дополнительные частные переменные
  2. методы производного класса принимают в качестве аргумента объект производного класса и возвращает объект производного класса.

Я могу сделать этот код работающим, но не полиморфным способом. Это упрощенная версия:

class Base 
{ 
protected: 
    int mInt; 
public: 
    Base(int iValue) : mInt(iValue) {} 
    virtual Base operator+(const Base otherBase) 
    { 
     Base result(otherBase.mInt + mInt); 
     return result; 
    } 

}; 

class Derived : public Base 
{ 
private: 
    double mDouble; 
public: 
    Derived(int iValue, double dValue) : Base(iValue) 
    { 
     mDouble = dValue; 
    } 
    Derived operator+(const Derived otherDerived) 
    { 
     Derived result(otherDerived.mInt + mInt, 
         otherDerived.mDouble + mDouble); 
     return result; 
    } 

}; 

int main() 
{ 

    Derived DobjectA(2,6.3); 
    Derived DobjectB(5,3.1); 
    Base* pBaseA = &DobjectA; 
    Base* pBaseB = &DobjectB; 
    // This does not work 
    Derived DobjectC = (*pBaseA)+(*pBaseB); 

} 

Как я могу создать классы для выполнения этой работы?

+1

возможно, это может помочь http://stackoverflow.com/questions/274626/what-is-object-slicing –

+0

Что вы ожидаете если 'pBaseB' фактически указывает на объект« Base »(или любой другой производный тип - кроме« Derived »- если на то пошло ...)? – Amit

+0

@Amit Я думаю, лучшим решением будет бросить исключение, если тип, указанный pBaseB, не является производным. – Msegade

ответ

2

Ключевым моментом здесь является, чтобы скрыть тип реального объекта за кадром, таким образом, что он может работать на в значимой без указания фактического типа.

Нам нужен способ, чтобы определить, какой тип «вещи», мы на самом деле имеем:

enum ThingType { TypeA, TypeB } ; 

Нам нужен класс, который является интерфейсом:

class ThingInterface 
{ 
public: 
    /* Type of the object */ 
    virtual ThingType Type() = 0; 
    /* Make a copy of ourselves */ 
    virtual ThingInterface* Clone() = 0; 
    /* Add rhs to this */ 
    virtual void Add(ThingInterface *rhs) = 0; 
    virtual ~ThingInterface(); 
}; 

Тогда нам нужен класс, который поддерживает наши фактические операции:

class Thing 
{ 
public: 
    /* Create empty object */ 
    Thing(ThingType type) { ... } 
    /* Create copy of existing object */ 
    Thing(ThingInterface* rhs) 
    { 
     pImpl = rhs->Clone(); 
    } 

    Thing operator+(const Thing& rhs) 
    { 
     Thing result(pImpl); 
     result.pImpl->Add(rhs.pImpl); 
     return result; 
    } 
private: 
    ThingInterface *pImpl; 
}; 

И теперь мы можем реализовать некоторый класс, чтобы сделать различные типы O е вещь:

class ThingTypeA: public ThingInterface 
{ 
public: 
    ThingTypeA() { ... }; 
    ThingType Type() { return TypeA; } 
    void Clone(ThingInterface *rhs) { ... } 
    void Add(ThingInterface *rhs) { ... } 
}; 


class ThingTypeB: public ThingInterface 
{ 
public: 
    ThingTypeA() { ... }; 
    ThingType Type() { return TypeB; } 
    void Clone(ThingInterface *rhs) { ... } 
    void Add(ThingInterface *rhs) { ... } 
}; 

Очевидно, что для реализации матрицы, вы должны иметь некоторые общие цели «заставить меня содержание ячейки X, Y», который реализуется как в ThingTypeA и ThingTypeB - а может быть, и что-то более умный когда дело доходит до выяснения того, какой тип результирующая матрица должна быть для TypeA + TypeB и т.д.

+0

Ницца .. но, как вы указываете, значение 'TypeA + TypeB' является проблемой. Это не имеет никакого смысла. Попытка собрать несовместимые типы с операциями как '+'/'Add' является ошибкой дизайна. – 4386427

+0

Нет, это не ошибка дизайна - проблема в том, что кто-то с знаниями домена (другими словами, знает, как лучше всего найти разреженные матрицы). Функция 'Add' должна либо преобразовать' rhs' в тот, который совместим с самим собой, либо использовать виртуальную функцию для получения данных в соответствующем формате для строки, столбца или ячейки, в зависимости от того, какую сложность при получении Лучше всего использовать данные по времени. –

+0

Хм ... Хорошо .. Ну, я должен признать, что давно я взял своего хозяина, который включал исследования редких матриц для электротехники, поэтому с тех пор все изменилось. Тем не менее, я убежден, что OP работает неправильно. – 4386427

-1

Чтобы сделать работу проблема строки, вы можете использовать динамическое приведение:

Derived DobjectC = *(dynamic_cast<Derived*>(pBaseA)) + *(dynamic_cast<Derived*>(pBaseB)); 
+0

Хорошо, это работает. Но это не решает проблему полиморфизма. Я не могу использовать указатель базового класса в любом месте, где может быть класс Derived. – Msegade

+0

Результат 'dynamic_cast' не гарантированно является допустимым указателем - он может быть nullptr, который вы весело разыгрываете без заботы в мире здесь. – Puppy

+0

@Puppy Да, конечно, вы правы. Но я не пытался ответить на вопрос о семантике dynamic_cast, так как это был бы еще один вопрос. В контексте этого вопроса решение компилируется и выполняется, как ожидалось. –

Смежные вопросы