Question

I have a C++ slicing problem. I'm new to C++, so maybe just too dumb to realize this can't be done.... I have tried a variety of workarounds, and my current best approach looks like below. (I need to do something like this to avoid changing a ton of interfaces in a very large legacy code base. Not claiming this is elegant style in any way!!)

Having troubles making this compile. Is the idea sound? Or is the entire approach doomed to failure? The constructors for references appear to be the issue. I've read Stroustrup's "C++ Programming Lanugage" (or at least what I thought were the relevant sections) but it didn't help.

class FOO {};

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

class BAR {
public:
    BAR(const FOO foo) : _foo(foo), _realFoo(&_foo) { }

BAR(const FOOSUBCLASS foosc) : _foosc(foosc), _realFoo(&_foosc) {} 
private:
    FOO _foo;
    FOOSUBCLASS _foosc;
    FOO& _realFoo;
};

The compiler doesn't like my _realFoo(&_foo) line. I'd like the reference to _foo, to just be the reference from the member variable in the class. Is that not possible in C++?

Here's the specific error from VS2005:

'initializing' : cannot convert from 'FOO *' to 'FOO &'
Was it helpful?

Solution

_foo is a FOO&.
&_foo is a FOO*.
The compiler cannot convert from 'FOO *' to 'FOO &'.
what you want is ..., _realFoo(_foo)

Unrelated: What you probably actually want is a std::unique_ptr<FOO> member instead. This will be much smaller, and much less error prone.

The struct as you have it now, contains a full and complete instance of FOO, and a full and complete instance of FOOSUBCLASS, and a reference. At least put the two FOO thingies in a union, so the size of BAR is only slightly bigger than the biggest FOO derivative. That would probably use the same memory as a unique_ptr<FOO>. Unfortunately, unions are a common source of bugs in C and C++.

Another problem is if someone comes along and writes

class FOOSOMETHINGELSE : public FOO {
   int buffer[1024];
};

Then you'll have to go and find the BAR class and change it and make it even bigger, and recompile all of your code that uses BAR everywhere. Whereas, if you used a unique_ptr<FOO>, then you won't have to change BAR or recompile anything. So smaller chance of error.

OTHER TIPS

There are several problems here. You correctly identify one of them as slicing, but slicing doesn't cause compile-time errors (which is what makes it so horrible...). Mooing Duck's answer should fix the compilation problem you're having, but the slicing problem remains. Suppose you have

FOO *x = new FOOSUBCLASS;
BAR y(*x);

This will cause slicing, because the following constructor will be called:

BAR(const FOO foo) : _foo(foo), _realFoo(&_foo) { }

and it takes its argument by value, meaning a copy from derived to base will occur.

Slicing occurs when you try to assign an object of derived class type to a base class object, e.g. by passing a derived class to a function that takes a base class by value as you're doing here. Basically any data members of the derived class object silently get "sliced off" because there simply isn't any room to fit them in a piece of memory that's only large enough to hold a base class object. When you need to work with objects that may actually be of a derived class, you must use either references our pointers (or smart pointers like shared_ptr or unique_ptr).

I'm pretty sure that all you want to do here is let a BAR object refer to an object that is either a FOO object or something derived from it -- correct? In that case (and assuming that the lifetime of the FOO object exceeds that of the BAR object), all you need is:

class BAR {
public:
    explicit BAR(FOO& foo) : _foo(foo) {}

private:
    FOO& _foo;
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top