Пример кода — это просто макет моей настоящей программы, которая пытается хранить различные классы из одного базового класса в базовом векторе. Затем используя виртуальный вызов функции, чтобы получить * 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;
}
Я искал лучшего понимания этого уже несколько часов, но все просто говорят о клонах, а это не то, что мне нужно.
Любая помощь будет оценена.
Нил
Чтобы быть в безопасности, используйте 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
}
}
Ваш код
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).
То, что вы пытаетесь достичь, а именно динамическое связывание метода независимо от статического типа, является основной целью виртуальных методов. Все, что вам нужно было сделать, это использовать указатели или ссылки на эти объекты в вашем контейнере.
Посмотрите на следующий код:
#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.
Надеюсь, что это проясняет.