Как использовать ковариантный возврат для извлечения производного класса из базового класса?

Пример кода — это просто макет моей настоящей программы, которая пытается хранить различные классы из одного базового класса в базовом векторе. Затем используя виртуальный вызов функции, чтобы получить * this, вернуть производную. Таким образом, мне не нужно несколько контейнеров.

    #include "stdafx.h"#include <iostream>
#include <vector>

class Base
{
public:
virtual Base* getThis() { return this; }
virtual void printClass() const { std::cout << "Base" << std::endl; }
};

class Derived : public Base
{
public:
virtual Derived* getThis() { return this; }
virtual void printClass() const { std::cout << "Derived" << std::endl; }
};int main(int argc, _TCHAR* argv[])
{
Base Bar;
Derived Foo;

typedef std::vector<Base*> vContainer;

vContainer Objects;
Objects.push_back(new Derived);

for (vContainer::iterator it = Objects.begin(); it != Objects.end(); ++it)
{
Bar = **it; // works to get Base but not wanted

// attempts
//Foo = it->getThis(); // the pointer selector doesnt work...
//Foo = static_cast<Derived>(**it);  // utterly confused!
}

Bar.printClass(); // prints base as expected
//Foo.printClass();  // Mean't to print Derived

std::cin.get();
return 0;
}

Я искал лучшего понимания этого уже несколько часов, но все просто говорят о клонах, а это не то, что мне нужно.
Любая помощь будет оценена.

Нил

1

Решение

Чтобы быть в безопасности, используйте dynamic_cast,

for (vContainer::iterator it = Objects.begin(); it != Objects.end(); ++it)
{
Bar* basePtr = *it;
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if ( derivedPtr ) // Check whether the dynamic_cast was successful.
{
// Use derivedPtr
}
}
1

Другие решения

Ваш код

Bar = **it; // works to get Base but not wanted

не получает объект из вектора в бар. Это просто назначение, почти идентичное этому (добавлен некоторый вывод):

class Base
{
public:
virtual Base* getThis() { return this; }
virtual void printClass() const { std::cout << "Base" << std::endl; }
Base& operator=(Base& one) { std::cout << "operator = is working" << std::endl; return *this;}
};

Итак, если вы хотите, чтобы указатель на объект сохранялся в векторе, не пытайтесь копировать объекты, скопируйте указатель (* iterator).

0

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

#include <iostream>
#include <vector>

class Base
{
public:
virtual void printClass() const { std::cout << "Base" << std::endl; }
};

class Derived : public Base
{
public:
Derived(){};
virtual void printClass() const { std::cout << "Derived" << std::endl; }
};int main()
{

typedef std::vector<Base*> vContainer;

vContainer Objects;
Objects.push_back(new Base);
Objects.push_back(new Derived);for (vContainer::iterator it = Objects.begin(); it != Objects.end(); ++it)
{
// prints Base on 1st iteration
// prints Derived on 2nd iteration
(*it)->printClass();
}

return 0;
}

Причина, по которой ваша попытка не сработала, заключается в том, что Bar была локальной переменной, а не ссылкой / указателем. Это означает, что размер Bar в памяти определяется во время компиляции и равен sizeof (Base). Присвоение ему производного объекта скопирует объект по значению и автоматически удалит дополнительную информацию, хранящуюся в производном объекте, и превратит ее в базовый объект (дополнительная информация просто не может быть сохранена в этом объеме памяти). Если bar имеет тип Base * и вы указали на объект Derived, то Bar-> printClass () выведет Derived.

Надеюсь, что это проясняет.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector