2012-04-04 4 views
0

Этот вопрос касается переопределения виртуального метода в производном классе с другим типом возвращаемого значения. Для следующего кода:Не удалось вернуть указатель производного класса при переопределении виртуального метода

class father { 
public: 
    virtual father* ref() { return this; } 
}; 

class child : public father { 
    virtual child* ref() { return this; } 
}; 

Когда я пытаюсь получить указатель непосредственно, г ++ (F15, г ++ 4.5) сообщает «недопустимый переход от отца к ребенку»

child m_child; 
father* pf = &m_child; 
child* pc = pf->ref(); 

Я понимаю, ref() в дочернем классе, и это, вероятно, просто несоответствие типа времени компиляции.

Однако, есть ли способ сделать это без явного использования литого типа?

Дополнительная информация: Я понимаю причину, по которой компилятор сообщает об этой ошибке. Мне нужно что-то из коробки, которая может получить доступ к данным в производном объекте без явного преобразования указателя.

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

У меня есть внутренний метод записи и проверки типа дочернего класса. Но я не хочу явно преобразовывать указатель.

Например, я хотел бы сделать что-то вроде этого:

// assuming pf is pointer pointed to an item fetch from a vector 
switch(fp->get_type()) { 
case child_type1: fp->ref()->list1.push(data); break; 
case child_type2: fp->ref()->list2.push(data); break; 
case child_type3: fp->ref()->list3.push(data); break; 
} 

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

Что я ожидаю: возможно, некоторые библиотеки ускорения могут делать похожие вещи по-другому, о которых я еще не знаю, или может быть стандарт C++ 11, но это должен быть специальный параметр компиляции?

+0

Я думаю, что я прекрасно понимаю, почему компилятор сообщает о несоответствии типа. Мне не нужно объяснять, что здесь происходит. Мне нужно что-то из коробки. Чтобы дополнительно объяснить это, PLS см. Добавленное дополнительное описание. –

ответ

2

Простой ответ «нет».

Вы потеряли дополнительную информацию (child* а не father*) о ref, когда вы выбросили m_child сек информацию о типе, сохраняя его как указатель на базу (pf).

Одна из причин, почему он никогда не будет возможно без броска этот пример:

class father { 
public: 
    virtual father* ref() { return this; } 
}; 

class childA : public father { 
    virtual childA* ref() { return this; } 
}; 

class childB : public father { 
    virtual childB* ref() { return this; } 
}; 

void should_never_compile(int i) 
{ 
    childA a; 
    childB b; 
    father pf; 
    if(i) { pf=&a; } 
    else { pf=&b; } 

    // This is evil and will not compile 
    childA * pa = pf->ref(); 

    //But this is OK: 
    childA * pa = dynamic_cast<childA*>(pf->ref()); 
} 

Если вы действительно хотите сделать это выполнимо без динамического броска вы можете просто скрыть динамический оттенок (но это меня пугает немного)

class father { 
public: 
    virtual father* ref() { return this; } 
    template<typename T> T* as() { return dynamic_cast<T*>(ref()); } 
}; 

child m_child; 
father* pf = &m_child; 
child* pc = pf->as<child>(); 
+0

Спасибо, вы мне предоставили что-то лучше! –

1

Ваша функция делает то, что вы ожидаете, и то, что вы говорите. Линия

child* pc = pf->ref(); 

есть проблема. Вы вызываете функцию «ref()» на указателе-отце, который возвращает (по типу) отцу *. Вы назначаете это - без конверсий - ребенку *. Реализация этой функции возвращает ребенка *, но , откуда вы называете это, что информация неизвестна, поскольку вы только знаете, что это отец *. Таким образом, тип возврата - это отец * (как указано у отца класса), и вы назначаете это без преобразования ребенку *. Вы можете сделать:

child *pc = m_child.ref(); 
father *pf = m_child.ref(); 
father *pf2 = pf->ref(); 
+0

Хорошо объяснил @ dascandy – Ricketyship

1

Проблема заключается в том, что в вызове pf->ref(), тип ref является: father* (father::*)().

То считается, что ref разрешен Статически является virtual способом с данной подписью. И эта подпись указывает, что она возвращает father*.

Таким образом:

int main() { 
    father f; 
    father* pf = &f; 

    child c; 
    child* pc = &c; 

    child* xf = pf->ref(); // compile-time failure 
    child* xc = pc->ref(); // okay 
} 

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

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