In the code example shown below - in Container
class, it owns (and is responsible fore destroying) two objects c, d
, which are subclasses of an abstract class B
. Container
object can create new ObjectDisplay
that takes a kind of B in its constructor. I can pass the abstract type B as a pointer into ObjectDisplay
and store it as a RAW pointer. But it's not ideal to store & use a raw pointer and always check if it's a null pointer. If B wasn't an abstract class, I could pass it in ObjectDisplay
as a reference (ie. ObjectDisplay (B& b)
). But since I can't change B, I wonder what's the aternative of storing B* object as a raw pointer in ObjectDisplay
?
// B is abstract
class B
{
public:
virtual int getDefault() = 0;
};
class C : public B
{
public:
int getDefault() override { return 1; }
};
class D : public B
{
public:
int getDefault() override { return 5; }
};
class ObjectDisplay
{
public:
ObjectDisplay (B* b) : object (b) {}
void someFunction()
{
const auto result = b->getDefault();
// do something
}
private:
B* object;
};
class Container
{
public:
void addDisplay()
{
displays.push_back (ObjectDisplay (&c));
displays.push_back (ObjectDisplay (&d));
}
private:
C c;
D d;
std::vector<ObjectDisplay> displays;
};
CodePudding user response:
If B wasn't an abstract class, I could pass it in ObjectDisplay as a reference
No, if B
is an abstract class, you can still pass it by reference. B& object
can be bound to an instance of B
's subclass. It behaves almost the same as pointers.
As quoted in cppref:
That is to say, if a derived class is handled using pointer or reference to the base class, a call to an overridden virtual function would invoke the behavior defined in the derived class.
Declare a member of B&
in ObjectDisplay
and construct it through a reference.
class ObjectDisplay
{
public:
ObjectDisplay (B& b) : object (b) {}
private:
B& object;
};
class Container
{
public:
void addDisplay()
{
displays.push_back (ObjectDisplay (c));
displays.push_back (ObjectDisplay (d));
}
};
See online demo
Aside:
Since you are passing a temporary ObjectDisplay
object directly constructed in push_back
, I recommend you to use emplace_back
.
void addDisplay()
{
displays.emplace_back (c);
displays.emplace_back (d);
}
CodePudding user response:
If
B
wasn't an abstract class, I could pass it inObjectDisplay
as a reference (ie.ObjectDisplay (B& b)
). But since I can't changeB
, I wonder what's the aternative of storingB* object
as a raw pointer inObjectDisplay
?
Just because B
is an abstract class does not mean you are required to pass it around and store it as a pointer. You CAN pass it around and store it as a reference as well. Polymorphism works with pointers AND references. And using a reference would indeed solve your nullptr
issue, eg:
class ObjectDisplay
{
public:
ObjectDisplay (B& b) : object (b) {}
void someFunction()
{
const auto result = object.getDefault();
// do something
}
private:
B& object;
};
class Container
{
public:
void addDisplay()
{
displays.push_back (ObjectDisplay (c));
displays.push_back (ObjectDisplay (d));
}
private:
C c;
D d;
std::vector<ObjectDisplay> displays;
};
As long as c
and d
outlive the ObjectDisplay
objects in displays
, you will be just fine, whether you use pointers or references.