2015-11-12 3 views
0
class Base { 
virtual void func1(); 
} 

class Derived : Base { 
void func1(); 
void func2(); 
} 

vector<Base *> vec; 
vec.push_back(new Base()), vec.push_back(new Derived()); 

Что такое правильный/чистый способ вызова func2 без зная, какой индекс соответствует классу? Есть ли такая конвенция? Я также хочу избежать использования typeid.Как вызвать вызов не переопределенной производной функции класса?

+2

Вы упомянули, вы не знаете, какой индекс соответствует какому классу, но все-таки нужно вызвать 'func2()'. Таким образом, вы не можете гарантировать, что 'func2()' будет вызываться для объектов 'Derived'. Какой результат вы ожидаете от вызова 'func2()' для объектов 'Base'? – alexeykuzmin0

+6

Возможно, вы захотите прочитать о [object] (https://en.wikipedia.org/wiki/Object_slicing) [slicing] (http://stackoverflow.com/questions/274626/what-is-object-slicing). –

+0

@ alexeykuzmin0 Я бы хотел узнать тип класса, может быть? Я открыт для любых других решений :) – mkmostafa

ответ

1

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

bool CallFunc2(Base* Bae){ 
    Derived* Der; 
    if (Der = dynamic_cast<Derived*>(Bae)) 
    {Der->func2(); return true;} 
    else 
    return false; 
} 

Это работает по принципу, что dynamic_cast возвращает нулевой указатель, если объект является приведение не может быть преобразован.

+0

Я использую вектор указателей! кто-то редактировал мой вопрос и менял его на объекты! – mkmostafa

+0

@SimonKraemer Нет, что кто-то не был мной. У меня возник вопрос, который я исправил. Затем кто-то переводит его обратно в первую ревизию. – mkmostafa

+0

@ mkmostafa Вы правы. Я неверно истолковал историю, поскольку исходная версия была сложена ... –

2

В вашем случае объекты нарезаны, как указано в ответе king_nak, поэтому нет безопасного вызова func2().
Но вы можете хранить указатели на базы вместо объектов базы - в этом случае вы можете использовать dynamic_cast:

std::vector<Base*> vec; 
vec.push_back(new Base()); 
vec.push_back(new Derived()); 

for (auto obj : vec) 
{ 
    Derived* d = dynamic_cast<Derived*>(obj); 
    if (d) 
    { 
     d->func2(); 
    } 
} 

Некоторая информация о dynamic_cast: link

PS: Кроме того, если вы хотите вызвать функцию func2() на Base объектах, я думаю, имеет смысл добавить глупую реализацию в класс Base и сделать функцию virtual.

+0

Я использую вектор указателей! кто-то редактировал мой вопрос !! – mkmostafa

+0

Хорошо, я удалю примечание – user4578093

+0

@mkmostafa в любом случае, вы можете использовать 'dynamic_cast' для решения этой проблемы. Кроме того, вы можете использовать 'reinterpret_cast' для решения исходной проблемы с нарезкой объектов, но он очень опасен – alexeykuzmin0

1

Если вы не хотите использовать RTTI на всех (в том числе dynamic_cast), вы можете моделировать его поведение, как Qt делает это с qgraphicsitem_cast

Outline:

class Base { 
public: 
    enum { Type = 0 }; 
    virtual int type() { return Type; } 
}; 
class Derived : public Base { 
public: 
    enum { Type = 1 }; 
    int type() { return Type; } 
}; 

template<typename T> 
inline T myobject_cast(Base *b) { 
    if (b) { 
     // Requires C++11 
     if (int(std::remove_pointer<T>::type::Type) == b->type()) { 
      return static_cast<T>(b); 
     } 
     /* Pre C++11 (might be UB, but works on many compilers, OpenSource and Commercial) 
     if (int(static_cast<T>(0)->Type) == b->type()) { 
      return static_cast<T>(b); 
     } 
     */ 
    } 
    return NULL; 
} 

// use: 
Base *b = new Base; 
Base *d = new Derived; 
Derived *o1 = myobject_cast<Derived*> (b); // NULL 
Derived *o2 = myobject_cast<Derived*> (d); // d 

Каждый класс требует уникальный Type участник для этого, чтобы работать.

Помните, что это не будет работать с «промежуточными» классами в иерархии. Только фактический, наиболее производный тип может быть отлит (например, DerivedDerived не может быть отлит до Derived, или Base, если на то пошло).

Вы также можете найти перегрузку Const удобно:

template<typename T> inline T myobject_cast(const Base *b) 
{ return (b && int(static_cast<T>(0)->Type) == b->type()) ? static_cast<T>(p) : 0; } 

const Base *cb = new Derived; 
const Derived *co = myobject_cast<const Derived *>(cb); 
+0

У меня была эта идея просто добавить функцию, которая получает тип в суперклассе, переопределяя его везде. Но я хотел чего-то более простого. Я думаю, что динамический бросок - это способ пойти;) .... Спасибо :) – mkmostafa

+0

Используйте 'T :: Type' вместо' static_cast (0) -> Type' (я не уверен, что ваша версия UB или нет). – Jarod42

+0

Этого не будет, к сожалению. Поскольку 'T'' Derived * ', он будет генерировать' Derived * :: Type', что неверно. Что касается UB, я тоже точно не знаю. Но Qt используется на самых разных платформах и поддерживает множество компиляторов, поэтому вполне безопасно использовать. Но, увы, не на 100% уверены ... –

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