2013-05-01 2 views
3

Я пытаюсь передать дочерний объект методу, но не знаю тип объекта раньше времени, кроме того, что он будет унаследован от родителя. Я могу установить тип как родительский, и компилятор счастлив, однако я теряю дочерние данные, когда этот процесс имеет место.C++ передать любой дочерний объект с родительским типом методу

class Parent{ 
public: 
Parent(int val); 
}; 

class Child{ 
public: 
Child(double childval, int parentval) 
}; 

Child::Child(double childval, int parentval) : Parent(parentval) 

Child childObj = new Child(cval, pval); 

int someOtherMethod(Parent pobj); 
someOtherMethod(childObj); // Looses child data but parent data persists. How to keep child data too? 

прекрасно, однако, если я прохожу childObj в someOtherMethod данные ребенка теряются, и только родительские данные сохраняются.

Я изучил виртуальные функции, динамическое связывание, «установил», но полностью запутался в том, в каком направлении я должен принимать.

Может кто-нибудь, пожалуйста, вернуть меня в нужное русло?

Спасибо.

+0

Опубликовать свой реальный код, желательно скомпилированный – yngccc

+0

«передать дочерний объект методу, но не знать тип объекта раньше времени» <это не означает, что тип является дочерним? ???? – marcadian

+0

@marcadian Тип объекта может быть любым из примерно 4 унаследованных типов: Child1, Child2 и т. Д. –

ответ

1

Проецируйте свои классы с умом, используйте полиморфизм и четко определенный интерфейс для получения данных из дочерних классов.

Однако, если вам нужно сделать, опущенными в C++, вы можете сделать это с dynamic_cast<T>:

int someOtherMethod(Parent *pobj); 
{ 
    Child1 *c1; 
    Child2 *c2; 
    Child3 *c3; 
    Child4 *c4; 



    if((c1= dynamic_cast<Child1*>(pobj)) != 0) 
    { 
     /* Do stuff here, pobj is instance of Child1 */ 
    } 
    else if((c2 = dynamic_cast<Child2*>(pobj)) != 0)) 
    { 
     /* Do stuff here, pobj is instance of Child2 */ 
    } 

    // ... 
} 

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

2

Как указал Nemanja Boric, один из вариантов заключается в использовании Dynamic Cast. Однако использование динамического переноса может быть дорогостоящим для некоторых компиляторов, таких как MSVC, которые будут запускать строку при оценке указателя.

Другой вариант, который у вас есть, - использовать Static Cast. Static Casts оценивается во время компиляции, поэтому практически нет затрат на их использование. Тем не менее, вам все равно придется определять тип вашего класса, чтобы знать, что его использовать. В вашем базовом классе вы можете иметь чистый виртуальный метод, называемый getType(), который возвращает нумерованное значение или целое число без знака, которое представляет собой идентификатор для класса. Затем вы можете проверить внутри «someOtherMethod», какой тип идентификатора прошел полученный класс, а затем выполнить приведение к этому типу класса.

Э.Г.

Определено в какой-то файл является перечисление с типами

enum ClassTypes 
{ 
    ClassType1, 
    ClassType2, 
    ... 
}; 

В качестве примечания: если вы не меняется, что указывает на PObj вы хотите, чтобы сделать указатель Уст. Это позволяет читателю знать, что вы не намерены его менять, а также- форма защитного программирования против вашего величайшего врага (самостоятельно), убедившись, что вы случайно не изменили его, а затем попытайтесь выполнить бросок на нем ,

int someOtherMethod(Parent * const pObj) 
{ 
    if(pObj == NULL) 
     return 0; 

    switch(pObj->getType()) 
    { 
     case ClassType1: 
     { 
      Class1 * const pClass = static_cast<Class1*>(pObj); 
      //Do stuff to class type 1 
      break; 
     } 
     case ClassType2: 
     { 
      Class2 * const pClass = static_cast<Class2*>(pObj); 
      break; 
     } 
    }; 

    return 1; 
} 

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

Вы должны рассмотреть дизайн самого класса. Возможно, какой-то код, который вы хотели выполнить в этой функции, вы могли бы выполнить в самом классе. Поэтому вместо того, чтобы знать тип, вы можете просто сказать:

pObj-> someOtherMethod(), где someOtherMethod - это чистая виртуальная функция, которую должны определить все ваши дети. Вы можете снова запустить дублированный код в нескольких определениях методов, и в этом случае могут понадобиться некоторые шаблоны проектирования, такие как шаблон NVI.

2

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

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

class Child1; 
class Child2; 

class Visitor 
{ 
public: 
    void DoStuff(Child1 & child1); 
    void DoStuff(Child2 & child2); 
}; 

class Parent 
{ 
public: 
    void DoStuff(Visitor & visitor); 
}; 

class Child1 : public Parent 
{ 
public: 
    void DoStuff(Visitor & visitor) 
    { 
    visitor.DoStuff(*this); 
    } 
}; 

class Child2 : public Parent 
{ 
public: 
    void DoStuff(Visitor & visitor) 
    { 
    visitor.DoStuff(*this); 
    } 
}; 

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

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