0

I want to do the equivalent of the following to initialize the data member my_abc (which I suspect won't work):

class ABC { // abstract base class
public:
    virtual ~ABC {};
}

class SomeClass {
public:
    SomeClass(ABC& abc); // argument will actually be instance of derived class
private:
    ABC my_abc; // needs to be set from constructor argument
}

SomeClass::SomeClass(ABC& abc) : my_abc(abc)
{...} // copy construct `my_abc` from argument

I suspect this won't work when a derived class of ABC is passed to the SomeClass constructor because the copy constructor of the derived class won't be called to initialize the my_abc member.

Am I correct? If so, what should I do?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Steve Emmerson
  • 7,702
  • 5
  • 33
  • 59
  • 5
    If `ABC` is really abstract, you can't have a member instance `ABC my_abc;`. What you can do is using a reference: `ABC& my_abc;`. If not your copy will degenerate to a simple `ABC`, that's called _splicing_. – πάντα ῥεῖ Sep 17 '14 at 20:23
  • @πάνταῥεῖ pretty sure you meant [*slicing*](http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c) (to divide), not *splicing* (to assemble). =P – WhozCraig Sep 17 '14 at 20:27
  • @WhozCraig Ooops, yes! _slicing_ of course. – πάντα ῥεῖ Sep 17 '14 at 20:28

1 Answers1

4

You said,

SomeClass(ABC& abc); // argument will actually be instance of derived class

and then, you have a member data

ABC my_abc;

If you initialize my_abc using abc, you will get a base class object that does not capture the derived class part. Checkout the issue of object slicing. Is that what you are hoping to accomplish? I think not.

As mentioned in the comment by πάντα ῥεῖ, you should store a reference to the base class.

ABC& my_abc_ref;

Then,

SomeClass::SomeClass(ABC& abc) : my_abc_ref(abc) {...}

shouldn't be a problem.

If you want to have a copy of the input object, you need to clone the input object and maintain the lifetime of the cloned object. You can use a smart pointer to accomplish that.

class ABC {
public:
    virtual ~ABC() {}
    virtual ABC* clone() const = 0;
};

#include <memory>

class SomeClass {
public:
    SomeClass(ABC& abc);
private:
    std::unique_ptr<ABC> my_abc;
};

SomeClass::SomeClass(ABC& abc) : my_abc(abc.clone()) {}

This just shows the mechanism. To create production quality code, you have to make policy decisions on the behavior of copy and move construtors, and copy and move assignment operators of SomeClass and implement them appropriately.

PS

The class ABC, as posted, is not an abstract base class. It does not have any pure virtual functions.

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Maybe mention that `ABC` obviously does not have any ellided additional pure-virtual member-functions and is thus not actually abstract... – Deduplicator Sep 17 '14 at 20:41
  • If it's really abstract, maybe use `ABC*` instead of `ABC&`, use some kind of "clone" function rather than a copy constructor, and destroy `my_abc` in `~SomeClass()`. – David K Sep 17 '14 at 20:41