'Alternatives for storing a class member as a raw pointer

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;
};


Solution 1:[1]

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);
    }

Solution 2:[2]

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?

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;
};

Online Demo

As long as c and d outlive the ObjectDisplay objects in displays, you will be just fine, whether you use pointers or references.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2