Как я могу привести родительский класс в качестве дочернего класса

Прошло много времени с тех пор, как мне пришлось писать код на C++, и я чувствую себя немного глупо. Я написал код, который похож, но не совсем, код ниже:

class Parent
{
    ...
};

class Child : public Parent
{
    ...
};

class Factory
{
    static Parent GetThing() { Child c; return c; }
};

int main()
{
    Parent p = Factory::GetThing();
    Child c1 = p; // Fails with "Cannot convert 'Parent' to 'Child'"
    Child c2 = (Child)p; // Fails with "Could not find a match for 'TCardReadMessage::TCardReadMessage(TCageMessage)'"
}

Я знаю, что это должно быть просто, но я не уверен, что я делаю неправильно.

8 ответов

Решение

Parent объект, возвращаемый по значению, не может содержать Child Информация. Вы должны работать с указателями, предпочтительно с умными указателями, поэтому вам не нужно убирать за собой:

#include <memory>

class Factory
{
    // ...

public:

    static std::auto_ptr<Parent> GetThing()
    {
        return std::auto_ptr<Parent>(new Child());
    }
};

int main()
{
    std::auto_ptr<Parent> p = Factory::GetThing();
    if (Child* c = dynamic_cast<Child*>(p.get()))
    {
        // do Child specific stuff
    }
}

Обратитесь к фрагменту кода ниже:

Child* c = dynamic_cast<Child*>(parentObject);

где, parentObject имеет тип Parent*

Убедитесь, что "parentObject" на самом деле имеет тип "Child", в противном случае - undefined-поведение.

Обратитесь за дополнительной информацией

Вы не можете, правда. Ваша фабрика вернула Parent объект, который был построен из Child объект c[*]. Часть Child уже удалена, так как возвращается main функция. Там нет никакого способа, чтобы восстановить это.

Возможно, вы хотите использовать указатели?

[*] Кроме этого, Child c(); объявляет функцию, она не определяет объект. Но это не ваш настоящий код, и я думаю, что у вашего реального класса есть параметры конструктора.

Я думаю, что проблема не в том, как вы пытаетесь сыграть роль, а в том, почему вы хотите сыграть в первую очередь. Код не имеет смысла - даже если он синтаксически действителен. Вы пытаетесь бросить "фрукт" в "яблоко" в контексте, где легко доказать, что у вас на самом деле нет яблока. Динамические приведения и тому подобное полезны только тогда, когда у вас есть указатель на "фрукт", который у вас есть основания для вещи, также "яблоко".

Вы можете разыграть с помощью конструктора Single Argument: т.е. (родитель работает, ребенок изучает) следующим образом:

#include <iostream>
using std::cout;

class Parent
{
    public:
    void goToWork()
    {
        cout<<"working\n";  // only parents work
    }
};

class Child : public Parent
{
    public:
    Child(const Parent& parentAddr){}
    void goToSchool()
    {
        cout<<"studying\n";   // only children studies
    }
};

int main(void)
{
    Child child(*(new Parent()));

    // here's a child working
    child.goToWork();
    return 0;
}

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

Вы не можете привести объект родительского класса к типу дочернего класса. Объект родительского класса - это... ну, объект родительского класса. Дочерний класс расширяет родительский класс, что означает, что объект родительского класса обычно "меньше", чем объект дочернего класса. По этой причине приведение (или реинтерпретация) родительского класса как дочернего класса не имеет никакого смысла.

Объясните, что вы пытаетесь сделать. Без объяснения ваш вопрос просто не имеет смысла.

Вы, вероятно, не хотите быть здесь на кастинге. Если у Parent есть какие-либо абстрактные методы, вы просто вызываете их, и производный класс автоматически обрабатывает их правильно.

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

Между прочим, я очень удивлен, что вы не получили ошибку компилятора в GetThing(), потому что вы объявили c как функцию, поэтому вы не возвращаете Parent.

Кроме того, кстати, если вы копируете по значению, вы будете "разрезать" таким образом:

Child c;
Parent p(c);
Child & c2 = dynamic_cast< Child& >(p); // throws bad_cast

Вы не можете использовать реальные объекты, но вы можете использовать указатели на объекты.

Для приведения указателей используйте такой код:

Child* c = reinterpret_cast<Child*>(p);
Другие вопросы по тегам