Reputation: 13
The code example is just a simple mock up of my actual program which attempts to hold varying different classes all from a single base class in a base vector. Then using a virtual function call to get *this, return the derived. This way I don't need multiple containers.
#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;
}
I've been looking for a better understanding of this for hours now but everyone just talks about clones, which is not what I'm after. Any help would be appreciated.
Neil
Upvotes: 1
Views: 94
Reputation: 363
What you're trying to achieve, which is dynamic binding of the method regardless of the static type, is the whole purpose of virtual methods. All you had to do is using pointers or references to those objects in your container. Look at the following code:
#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;
}
The reason why your attempt didn't work is that Bar was a local variable and not a reference/pointer. This means the size of Bar in the memory is determined at compile time and is sizeof(Base). Assigning a Derived object into it will copy the object by value and automatically delete the extra information stored in a Derived object and making it into a Base object (the extra information simply can't be stored in that amount of memory). If bar was of type Base* and you made it to point to a Derived object then Bar->printClass() would print Derived.
Hope that clarifies it.
Upvotes: 0
Reputation: 6407
Your code
Bar = **it; // works to get Base but not wanted
does not get object from vector to Bar. This is just assignment almost identical to this one (some output added):
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;}
};
So, if you want to have pointer to object stored in the vector do not try to copy objects, copy pointer (*iterator).
Upvotes: 0
Reputation: 206567
To be safe, use 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
}
}
Upvotes: 1