2014-10-12 2 views
7

Я хочу знать, что представляет собой современный эквивалент C++ 11 экземпляра Java. Я видел это SO post, но он довольно старый и задавался вопросом, есть ли более современное, лучшее решение в C++ 11?Что такое эквивалент C++ 11 экземпляра Java

Я надеялся, что есть возможность использовать конструкцию коммутатора, не прибегая к ручному классу enum.

class A { 

}; 

class B : public A { 

} 

class C : public A { 

} 

on_event(A& obj) 
{ 
    switch (obj) { 
     case A: 
     case B: 
     case C: 
    } 
} 

У моего базового класса нет виртуальных методов или функций. Я представляю дерево выражений для синтаксического анализатора, а базовый класс - только полиморфный держатель - как ADT в Haskell/OCaml.

+3

Вы запрашиваете 'dynamic_cast <>'? Это не C++ 11. –

+0

Ничего не изменилось: в стандарте C++ нет отражения. Если вы хотите включить информацию о типе времени выполнения, вы 'dynamic_cast' – quantdev

+0

Может быть интересно: http://stackoverflow.com/q/25495733/596781 –

ответ

12

Тот же ответ все еще применяется, и всегда был, как это в C++:

if (C * p = dynamic_cast<C *>(&obj)) 
{ 
    // The type of obj is or is derived from C 
} 
else 
{ 
    // obj is not a C 
} 

Эта конструкция требует A полиморфными, т.е. иметь виртуальные функции-члены.

Также обратите внимание, что это поведение отличается от сравнения typeid(obj) == typeid(C), так как последние проверяют точное тождество типа, тогда как динамическое преобразование, а также Java instanceof, проверяют только для целевого типа как базовый класс типа самого производного объекта.

+1

, он также требует «RTTI», что является видом боли для некоторых пользователей C++. – user2485710

+1

@ user2485710: Я не думаю, что это утверждение имеет смысл в контексте * языка * C++. Код действителен C++, без квалификации. –

+1

, если у вас нет «RTTI», эта вещь не будет работать, не имеет значения, что вы рассматриваете, она просто необходима, чтобы позволить этому фрагменту кода работать должным образом. – user2485710

-1

Если вы хотите ограничить себя известными во время компиляции типами (вместо того, чтобы работать с указателями на экземплярах классов с помощью vtables), то в C++ 11 и более поздних версиях есть эквивалент instanceof: это std::is_base_of.

Возможно, вы также захотите зарегистрироваться std::is_convertible и std::is_same.

+3

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

+0

@PeterT: Полностью не согласен. То есть, в C++, особенно в Modern C++, мы делаем многое с известными типами компиляции, поэтому это вполне правильный ответ (даже если он должен быть отредактирован). – einpoklum

0

В C++ простые старые данные (POD) не имеют информации о времени исполнения. Все описанные классы принимают ровно 1 байт и имеют идентичные представления во время выполнения в любом компиляторе с пустым оптимизацией базового класса.

Как таковое вы не можете сделать.

Добавление виртуального деструктора в базовый класс добавляется в RTTI и dynamic_cast.

Добавление поля enum или int к базе, которая инициализируется по-разному для каждого производного класса.

Еще один вариант заключается в создании функции шаблона и хранить указатель на него, например, так:

using my_type_id=void(*)(); 
template<class>void get_my_type_id_helper(){}; 
template<class T> my_type_id get_my_type_id(){return get_my_type_id_helper<T>;} 

, а затем хранящий my_type_id в A инициализируется соответствующим образом. Это заново изобретает RTTI, и, поскольку вам нужно больше возможностей, вы подойдете к накладным расходам C++ RTTI.

В C++ вы платите только за то, что просите: вы можете запросить классы без RTTI, которые вы сделали, и получить его.

RTTI - информация о времени выполнения. POD - это простые старые данные, термин C++ 03. Многие классы не являются POD: простой способ заключается в добавлении деструктора virtual. C++ 11 имеет более мелкозернистую стандартную компоновку и агрегированные термины.

Технически RTTI и POD не являются противоположностями друг от друга: существуют классы без RTTI, которые не являются POD.

Обратите внимание, что в MSVC есть опции, чтобы не генерировать RTTI, и его агрессивный складной склад Comdat может нарушить ручной RTTI, который я сделал выше, в обоих случаях в нарушение стандарта.

-1

Не делайте этого. В большинстве случаев вы должны пересмотреть свой дизайн, когда задаете instanceof или dynamic_cast.

Почему? Вы, скорее всего, нарушаете Liskov's substitiontin principle.

Как об этом подходе:

class A { 
    public: 
    virtual void action(); 
    virtual ~A(); 
}; 

class B : public A { 
    public: void action() override; 
}; 

class C : public A { 
    public: void action() override; 
}; 

void on_event(A& obj) 
{ 
    obj.action(); 
} 

Обратите внимание, что, как @Yakk указал, что вам нужно, по крайней мере один virtual метод в любом случае, чтобы получить динамический полиморфизм. И есть правило, в котором говорится: когда у вас есть хотя бы один виртуальный метод, всегда также записывайте виртуальный деструктор в базовый класс.

Вы можете сделать все это с помощью шаблонов и специализации или пометки типа, но я беру с вашего вопроса - исходя из Java - вы еще не хотите туда идти. Вы действительно как виртуальных методов, не так ли? Извините, что вы должны отметить их на C++.

+0

Я не думаю, что программа, состоящая из 3 классов (A, B, C), нарушает LSP и может считаться хорошим дизайном. Я хотел, чтобы часть LSP была заложена в заблуждение (речь идет о прямой альтернативе instanceof для C++ 11, и ваши предупреждения уже упоминались в ссылке), но кто-то может сочтет это полезным. – m039

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