c++ Является ли класс производным от определенного класса?

Возможно ли то, чего я пытаюсь достичь. Это проблема:

class Content{};

class Content1 : public Content{};
class Content1_1 : public Content1{};
class Content1_2 : public Content1{};

class Content2 : public Content{};
class Content2_1 : public Content2{};
class Content2_2 : public Content2{};

class Container{
public:
    Content* c;
};

Можно ли определить, указывает ли указатель класса Container на объект класса Content1 или на объект класса, производного от Content1?

Спасибо.

ИЗМЕНИТЬ:

Если я ищу тип указателя в классе container, он рассматривается как тип content, хотя на самом деле это может быть тип content1 или content2, поэтому dynamic_cast не работает.

class content{};
class content1 : public content{};
class content2 : public content{};

class container{
public:
    content* c;
};

int main(void)
{
    container* x = new container;
    x->c = new content2;

    if( dynamic_cast<content1*>((content1*)x->c) == NULL){
        //This doesn't fail, eventhough 'content1' and 'content2' shouldn't be compatible.
        //This means that every class, derived from 'content' will be treated as 'content1' when using dynamic_cast.
    }

    return 0;
}

person JMRC    schedule 30.03.2013    source источник
comment
Я не понимаю, в чем проблема? А где указатель класса Base?   -  person ashgkwd    schedule 30.03.2013
comment
Я не понимаю редактирования. Не могли бы вы расширить немного больше?   -  person Andy Prowl    schedule 30.03.2013
comment
Как вы искали тип указателя в классе контейнера — вы использовали typeid или вы использовали dynamic_cast — если вы использовали dynamic_cast — можете ли вы вставить строку кода? typeid явно не будет работать.   -  person user93353    schedule 30.03.2013
comment
@ user93353 Я вставил пример.   -  person JMRC    schedule 30.03.2013
comment
Вы должны делать if( dynamic_cast<content1*>(x->c) == NULL), а не if( dynamic_cast<content1*>((content1*)x->c) == NULL)   -  person Andy Prowl    schedule 30.03.2013
comment
@AndyProwl: Затем я получаю эту ошибку (Visual Studio): ошибка C2683: 'dynamic_cast': 'content' не является полиморфным типом.   -  person JMRC    schedule 31.03.2013
comment
@JMRC: я рассказал об этом в своем ответе. Ваш базовый класс должен иметь хотя бы одну виртуальную функцию, и общепринятой практикой является определение виртуального деструктора. Так же, как я показываю в ответе   -  person Andy Prowl    schedule 31.03.2013


Ответы (4)


Если ваши типы полиморфны (т.е. имеют хотя бы одну функцию virtual), вы можете использовать dynamic_cast<>. Результатом dynamic_cast<> будет нулевой указатель (т.е. nullptr для C++11, NULL для C++03) в случае, если указанный объект на самом деле не является экземпляром указанного класса или его производного класса:

Container cont;
Content1* pContent1 = dynamic_cast<Content1*>(cont.c);
if (pContent1 != nullptr)
{
     // cont.c points to an instance of Content1 
     // or a class derived from Content1
}

Обычная практика заключается в том, чтобы сделать деструктор вашего базового класса виртуальным, чтобы объекты класса, производного от вашего базового класса, могли быть deleted через указатель базового класса (если деструктор не virtual, попытка это приводит к неопределенному поведению):

class Content //Abstract.
{
public:
    virtual ~Content() { }
//  ^^^^^^^
};
person Andy Prowl    schedule 30.03.2013
comment
dynamic_cast не работает, я отредактировал вопрос, чтобы прояснить ситуацию. - person JMRC; 30.03.2013
comment
@JMRC Это действительно работает, вам просто нужно удалить C-приведение в вашем редактировании. (без замены). - person Oberon; 31.03.2013
comment
Это действительно была виртуальная функция, которой не хватало, теперь я могу использовать dynamic_cast. У меня не было этой ошибки (Visual Studio): error C2683 в моей реальной программе при использовании dynamic_cast, потому что там я использовал виртуальные функции. Теперь я знаю, в чем настоящая проблема. Спасибо. - person JMRC; 31.03.2013
comment
@JMRC: хорошо, рад, что помог :) - person Andy Prowl; 31.03.2013


Если вам нужно знать точный тип полиморфного класса во время выполнения, вам следует переосмыслить свой дизайн. Обычно лучше либо держать объекты разных типов в разных контейнерах (дополнительно или вместо одного центрального контейнера), либо добавлять в каждый из производных классов виртуальную функцию, которая выполняет действие, где вам пришлось бы различать типы.

В FAQ по C++ есть запись, которая может вам помочь: У меня есть неоднородный список объектов, и мой код должен делать с объектами вещи, специфичные для класса. Похоже, что это должно использовать динамическую привязку, но не может понять это. Что мне делать?

person Oberon    schedule 30.03.2013
comment
В некоторых случаях виртуальные функции сработали бы, но, к сожалению, не здесь. Я обновил вопрос, чтобы все было понятно. - person JMRC; 30.03.2013

Если вы хотите увидеть, указывает ли Content* на объект класса, производного от класса Content2, просто приведите его к dynamic_cast и посмотрите.

Это работает:

#include <iostream>
#include <typeinfo>

using namespace std;

class Content{public: virtual ~Content(){}};

class Content1 : public Content{public: virtual ~Content1(){}};
class Content1_1 : public Content1{public: virtual ~Content1_1(){}};
class Content1_2 : public Content1{public: virtual ~Content1_2(){}};

class Content2 : public Content{public: virtual ~Content2(){}};
class Content2_1 : public Content2{public: virtual ~Content2_1(){}};
class Content2_2 : public Content2{public: virtual ~Content2_2(){}};

class Container{
public:
    Content* c;
};

int main()
{
    Content* cnt=new Content2_1;
    if(dynamic_cast<Content2_1*>(cnt))
        cout << "True" << endl;
    return 0;
}
person Johnny Mnemonic    schedule 30.03.2013