How do I cast from a base class object to a derived class object?

Hi,

I have two classes, one derives from the other.

Object00.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once
#include <string>
#include <vector>
using namespace std;

class Object00
{
protected:
	int index, status;
	string name;

	vector <string> vectorAdditionalMessages;
public:
	Object00();
	~Object00();
}

Object01.h
1
2
3
4
5
6
7
8
9
10
#pragma once
#include "Object00.h"

class CaveObject01 : public Object00
{
	vector<string> vectorStatusMessages;
public:
	Object01();
	~Object01();
};


in my code I have a vector of Object00 to which I add objects of both Object00 and Object01
1
2
3
4
5
6
7
8
9
10
11
vector<Object00> vectorObjects;

// Object00 object1 is a correctly and fully initialized Object00
// Object00 object2 is a correctly and fully initialized Object00
// Object01 object3 is a correctly and fully initialized Object01
// Object01 object4 is a correctly and fully initialized Object01

vectorObjects.push_back(object1);
vectorObjects.push_back(object2);
vectorObjects.push_back(object3);
vectorObjects.push_back(object4);

So far so good.
I can look at the vectorObjects elements while debugging and see each element and its values; of course for object3 and object4 I can only see the members they inherit from Object00.

Now, I access an element from the vector
 
Object00 object = vectorObjects.at(2);

and I get object3. Again, I can only see the members it inherits from Object00.

So I want to cast object back to an Object01 so I can see its Object01 member.
After some searching, I think I need to do the following:
1
2
3
4
Object00 object = vectorObjects.at(2);
Object00 *pObject = &object;

Object01 *pObject01 = dynamic_cast<Object00*>(pObject);

Now, I get a complaint that
"the operand of a runtime dynamic_cast must have a polymorphic class type"
and found a couple of pages that said I needed a virtual destructor or function
so I put virtual in front of the Object00 destructor and now it runs but pObject01 shows no data whatsoever after the cast.

What's going on? Please be detailed in the code you give me.

If I do a static_cast (removing the virtual modifier), pObject01 shows the Object00 members' data and the Object01 members but not their data.
Last edited on
If you have a base class object, there is no way to "cast" it to a derived class object. In that case you would need to create a derived class object.

If you're asking how to cast a base class pointer that is pointing to a derived class object to a derived class pointer, use static_cast if the cast can't fail, or dynamic_cast if it can.

http://en.cppreference.com/w/cpp/language/static_cast
http://en.cppreference.com/w/cpp/language/dynamic_cast

This has nothing to do with windows programming.
In your code, you have a vector of Object00's. As I mentioned above, there is no way to cast an object of base type to an object of a derived type.

Casting occurs on pointers or references. Casting a pointer to a base object which actually points to a base object to a pointer to derived object will fail. It doesn't point to a derived class object; it points to a base class object.

As to the error message you're getting, the base class must have at least one virtual function for dynamic casting to be possible. (And if you have a class tree meant to be treated polymorphically, a virtual destructor is pretty much required.)
Last edited on
Hi,

My first question is: Should you have inheritance at all? Inheritance implies an "IS A" relationship - just wanted to confirm this to start with. To me , it looks like your second class (Object01) is a collection of the first class (Object00), or is at least produced from Object00 data. So this is an example of a "USING" relationship - the object of type Object00 is a parameter of a function that puts info into your vector. There is also the "HAS A" relationship which means that a class has a member variable of the type of another class. IMO this doesn't seem to apply here

using namespace std;

Don't do this. Lots written as to why that is so. Google.

The following isn't good practise either:

8
9
10
protected:
	int index, status;
	string name;


Always make member variables private. If necessary provide accessor or mutator functions to manipulate them. It may not be necessary if you use an initialiser list in the constructors or have a function that outputs the value member variables.

So I want to cast object back to an Object01 so I can see its Object01 member.


This doesn't make sense: If you have an Object00, the Object01 doesn't exist, do you mean the other way around?

The member variables of both classes are private or protected so the only way to get at them through an object is via an accessor function.

As I allude to earlier, none of this applies to your current problem, just helps out with your understanding.

HTH
Thank you for replying.

First point:
Yes, Object01 IS_A Object2 in the same way that given class Employee and class Manager : public Employee Manager IS_A Employee (assume Manager has a member that Employee doesn't need, last_years_bonus, perhaps). I have simplified the members of the classes for simplicity so the IS_Aness probably is not as evident as it might be. I used a vector in both base and derived classes because I thought the issue might be caused by using vector although that doesn't make sense and in fact I just tested it by giving Object01 a public int member and it doesn't show its value either.

Second point:
I'll look into why using
 
using namespace std;

is a bad idea; I use to avoid having to preface everything like this
 
std::string name;

which, as far as I knew up to now, is just a waste of time and effort.

Third point:
I am coming from Java and in Java private members are not inherited. I'll change my ways.

Fourth point:
As far as the cast I want to do:
My problem may be that I am coming from Java and in Java what I want to do is absolutely normal: you create an ArrayList (Java's vector) of the base class, then you add objects of the base class and any derived class to the ArrayList (add Managers and Employees to an ArrayList of Employees). You get a Manager object out as an Employee object but it is still a Manager object and you can cast it from the Employee object back to a Manager object to see its last_years_bonus member with a simple cast :
 
objectManager = (Manager)objectEmployeeFromArrayList;

This requires you to know that the element you got out is indeed a Manager, which can be done easily with Java's instanceof cast:
1
2
3
4
if(objectEmployeeFromArrayList instanceof Object01)
{
    objectManager = (Manager)objectEmployeeFromArrayList;
}

Isn't this something C++'s inheritance is suppose to do, too? I ran into a couple of sites that said if you need to cast like this your code is wrong and I don't understand that because, as I said, this sort of thing is a fundamental use of inheritance in Java.
Last edited on
Hi,

cire is vastly more qualified than me to answer questions about OOP design. Although I have heard about code with casting or RTTI could be redesigned.

I didn't see his posts while I was doing mine.

which, as far as I knew up to now, is just a waste of time and effort.


It brings in the whole std namespace which has the whole STL in it. It can cause naming clashes for variables & function names, which defeats the purpose of having namespaces. Ideally one should put their own stuff into their own namespaces. If you look at code posted by the experts on this site & others, you will see they always do std::string as an example.

I am coming from Java and in Java private members are not inherited.


They are not inherited in C++ either. When you have inheritance, the idea is to call base class constructors from derived class constructors initialiser list. If each class' constructor initialises all it's members, this should prevent object slicing.

The reason why public and protected member variables are bad is because future alterations to code can break existing code. One is much better off having a function to access a private variable, because it gives one much leeway to cope with future changes. There is a lot written about this also.

This requires you to know that the element you got out is indeed a Manager, which can be done easily with Java's instanceof cast:


I do know that C++ allows one to declare functions which has a parameter that is a pointer to a base class. Then call the function with a pointer to a derived class. The correct virtual function is called. This is really handy, because one can make a few functions in the base class, rather that make functions in every derived class.

Not sure how much of this you know already, just putting ideas out there.
Hi Cire,

Thank you for responding, but you didn't read my post: if you had read my post, you would know that:

although I didn't mention pointers in the subject (to keep the subject shorter), I did use pointers in my attempt to cast:
 
Object01 *pObject01 = dynamic_cast<Object00*>(pObject);


and

I did use a virtual function in the base class:
"...so I put virtual in front of the Object00 destructor and now it runs but pObject01 shows no data whatsoever after the cast."

Also, I found both of the pages you gave links to; they show, as far as I can see, the same way to cast as I am trying to use except that they are using structs, not classes, and they use references, not pointers. I tried references instead of pointers and it didn't help.

You are correct that "This has nothing to do with windows programming" and I'm sorry I put it in the wrong forum.

Any more detailed help you can give me?
Hello again,

I thought about how to do this without RTTI or casting, and came up with this:

Keep the names of virtual functions general (they apply to all the derived classes), but the specialisation occurs in the actual code of the functions in derived classes.

For example the base class CEmployee might have virtual functions like PrintStaffDetails(pEmployee* EmployeeObj); and CalculateStaffPay(pEmployee* EmployeeObj); etc. Then redefine those functions in the derived class to specifically do what is needed for that particular class. This way there is no need to find out the type of an object (whether it be by RTTI or casting), the correct virtual function is called as described in my last post. So you can still have a container (vector, map, unordered_set etc) of smart pointers to all the different types of Employees, the correct function is called. Use Smart pointers rather than new and delete.

So this make your code scalable, clients can add as many new classes as they like, no need to change your code; there is no need for switch statements to decide what to do.

The virtual functions don't necessarily have to be pure, nor do they have to exist only in the base class. Imagine a multi discipline consultancy with Architects, several types of Engineers, town Planners and Corporate Staff etc. Things that only apply to Architects can be implemented as virtual functions in the CArchitect Class rather than the base class CEmployee.

I did use a virtual function in the base class:
"...so I put virtual in front of the Object00 destructor and now it runs but pObject01 shows no data whatsoever after the cast."


Have you provided public functions which provides access to your member variables which are hopefully by now allprivate ?

Hope all goes well :+)

Edited function decalrations
Last edited on
Thank you for responding, but you didn't read my post: if you had read my post, you would know that:

Oh, I read the OP. I know that you have a vector of base class objects that will always be base class objects. No amount of contrived manufacturing of pointers (or references) is going to make those base class objects anything but base class objects, so casting is a moot subject. The link and information supplied was intended to point you in a different direction, but I seem to have left out the bit about object slicing (which you should google.)


that they are using structs, not classes

structs are classes. classes are structs. The only difference is the default access level.

Without espousing the design, here is an example of how objects might be stored and cast:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <vector>
#include <memory>
#include <random>
#include <array>

struct a
{
    virtual ~a() = default;
};

struct b : public a {};
struct c : public a {};


using pointer_type = std::unique_ptr<a>;
using vector_type = std::vector<pointer_type>;

pointer_type random_class()
{
    static std::mt19937 gen((std::random_device())());
    std::uniform_int_distribution<unsigned> dist(0, 2);

    switch (dist(gen))
    {
    case 0: return pointer_type(new a);
    case 1: return pointer_type(new b);
    case 2: return pointer_type(new c);
    }
}

const char* identity(const a* object)
{
    if (const c* o = dynamic_cast<const c*>(object))
        return "c";

    if (const b* o = dynamic_cast<const b*>(object))
        return "b";

    return "a";
}

template<typename iter_type>
void display(iter_type beg, iter_type end)
{
    std::cout << "{ ";
    while (beg != end)
        std::cout << identity((beg++)->get()) << ' ';
    std::cout << "}\n";
}

int main()
{
    vector_type v;
    for (unsigned i = 0; i < 10; ++i)
        v.emplace_back(random_class());

    display(v.begin(), v.end());
}


http://ideone.com/myaPd1


@cire

I think the OP had a vector that was declared as taking pointers to the base class, but contained pointers to various types of derived classes, so I was proposing this could be easily done with virtual functions.
TheIdeasMan wrote:
I think the OP had a vector that was declared as taking pointers to the base class, but contained pointers to various types of derived classes, so I was proposing this could be easily done with virtual functions.


From the OP:
in my code I have a vector of Object00 to which I add objects of both Object00 and Object01

1
2
3
4
5
6
7
8
9
10
11
vector<Object00> vectorObjects;

// Object00 object1 is a correctly and fully initialized Object00
// Object00 object2 is a correctly and fully initialized Object00
// Object01 object3 is a correctly and fully initialized Object01
// Object01 object4 is a correctly and fully initialized Object01

vectorObjects.push_back(object1);
vectorObjects.push_back(object2);
vectorObjects.push_back(object3);
vectorObjects.push_back(object4);


The latter 2 additions to vectorObjects result in object slicing.
@cire

Ok no worries, so we need to educate the OP about properly initialising objects. I mentioned earlier about initialiser list calling base class constructors.

I haven't time right now to do an example, but will once I get home from work.

Regards
Hi MsPhelix,

http://publib.boulder.ibm.com/infocenter/comphelp/v101v121/index.jsp?topic=/com.ibm.xlcpp101.aix.doc/language_ref/cplr388.html


http://stackoverflow.com/questions/15777635/c-calling-base-class-constructors


This shows an example of calling a base class constructor from the initialiser list of a derived class.

Some things to note:

An initialiser list is introduced with a colon after the parameter list of a constructor.

All of your classes should have a constructor that uses an initialiser list to initialise all of the class member variables in the same order they were declared.

Also, they should call any base class constructors in order form the top of the inheritance tree working down, so that member variables are initialised (they should all be private)

C++11 also has the ability to inherit constructors, and to have delegating constructors.

Hope this helps a bit, again I don't know how much you know - apologies if you have already been through this in Java (I don't know any Java)

Topic archived. No new replies allowed.