John
John

Reputation: 5913

How to instantiate an instance of a subclass in a member variable in C++?

I have a huge C++ code base I'm working with.

I want to introduce a new subclass, and use it in a variety of different contexts, however my Java trained mind is having trouble with this in C++.

I wish to minimize code changes. So, my main class of interest (BAR below) has a member variable of class FOO. I wish to make a subclass of FOO called FOOSUBCLASS. In java this is trivial. Objects are stored by reference by default. This code does not do that (as seen below) can I massage this code, without changing interfaces (and without introducing references) and still make my application work?

class FOO {
};

class FOOSUBCLASS : FOO {
public:
    FOOSUBCLASS(const int id) {_id = id;}
private:
    int _id;
};

class BAR {
public:
    BAR(const FOO foo) { _foo = foo;}
private:
    FOO _foo;
};

Below, is my main:

FOOSUBCLASS fsc(1);
BAR b(fsc);

But this doesn't compile in VS2005. It says:

'type cast' : conversion from 'FOOSUBCLASS *' to 'const FOO &' exists, but is inaccessible

Get same compiler error if I add the obvious other constructor to BAR

BAR(const FOOSUBCLASS foo) { _foo = foo;}

My understanding of C++ is that it will copy the data from FOOSUBCLASS into an object of class FOO. (using the assignment operator, or a class overridden version of it) But in my case, I have additional member variables in FOOSUBCLASS (and some overridden member functions) so I just don't want it to do that. I want my member variable _foo to truly be of type FOOSUBCLASS in some contexts, and FOO in others. Is this even possible?

Thanks for your thoughts.

Upvotes: 3

Views: 2326

Answers (4)

BigBoss
BigBoss

Reputation: 6914

First in C++ classes by default use private to inherit from their base classes, this means that FOOSUBCLASS is a FOO but conversion is internal and is not accessible to you. So first convert class FOOSUBCLASS : FOO to class FOOSUBCLASS : public FOO and second is in Java every this is reference so you can say

FOOSUBCLASS fs;
FOO f = fs;

but in C++ we have references and non-references and using FOO f create a non-reference that is actually an object so FOO f = fs only copy FOO part of fs into f and does not cause a FOO reference to a FOOSUBCLASS to achieve this you should use pointer or reference or smart pointers. For example you can say:

FOOSUBCLASS* fs = new FOOSUBCLASS;
FOO* f = fs;   // Use pointer is OK
FOO& rf = fs;  // A reference of fs as a FOO
std::auto_ptr<FOO> spf( fs );  // OK, but for this destructor must be virtual

Upvotes: 1

bobestm
bobestm

Reputation: 1334

Further to user sehe, consider passing a reference rather than passing by value to constructor of BAR.

class BAR { public: BAR(const FOO& foo) { _foo = foo;} private: const FOO& _foo; };

Upvotes: 0

Tom W
Tom W

Reputation: 1334

You can't do it the way you've written it now, sorry. This is called "slicing", and more info about it can be found here: What is object slicing?

If you want your _foo member to be polymorphic, you'd need to use a pointer or a reference. Be aware of lifetime management when you do things like this of course.

Upvotes: 2

sehe
sehe

Reputation: 393799

Make the base class public

class FOOSUBCLASS : public FOO {
public:
    FOOSUBCLASS(const int id) {_id = id;}
private:
    int _id;
};

Also, beware of slicing in the BAR constructor

Assign to pointer/reference to avoid that:

class FOO
{
};

class FOOSUBCLASS : public FOO
{
public:
    FOOSUBCLASS(const int id) : _id(id) {}
private:
    int _id;
};

class BAR
{
public:
    BAR(const FOO& foo) : _foo(foo)
    {
    }
private:
    FOO& _foo;
};

Note: I used initializer-list syntax instead of assignments in the constructor body.

Upvotes: 2

Related Questions