3

As the answers pointed out, this is a dumb mistake I made that has nothing to do with polymorphism or smart pointer. The corrected version is in the accepted answer.

============== Original question ==================

I am trying to make smart pointer work with polymorphism. In the following prototype code, the implementation for pure virtual function Base::print() should be in the memory block of Derived object. DerivedWrap have access to the pointer to the Derived object.

Why can not DerivedWrap::print() access the function implementation?

using namespace std;

class Base 
{
public:
    virtual void print() = 0;
};

class Derived : public Base 
{
public:
    Derived(int in) : i(in) {}

    void print() {
        cout << "int is " << i << endl;
    }

private:
    int i;
};

class DerivedWrap 
{
public:
    DerivedWrap() : DerivedWrap(make_unique<Derived>(2)) {}
    DerivedWrap(unique_ptr<Base> pBase) : _pBase(move(pBase)) {}

    void print()
    {
        _pBase->print();
    }

private:
    unique_ptr<Base> _pBase;
};

int main() 
{
    DerivedWrap pDW1();
    pDW1->print(); // error: request for member ‘print’ in ‘pDW1’, which is of non-class type ‘DerivedWrap()’

    DerivedWrap pDW2(make_unique<Derived>(2));
    pDW2->print(); // error: base operand of ‘->’ has non-pointer type ‘DerivedWrap’
    return 0;
}

JeJo
  • 30,635
  • 6
  • 49
  • 88
Pracka
  • 159
  • 1
  • 8

3 Answers3

7

You have a couple of issues.

  • This DerivedWrap pDW1(); is a function declaration whose return type is DerivedWrap. It is not calling its default constructor which you are expecting to. You need simply
    DerivedWrap pDW1;  // calls the default constructor
    // or 
    // DerivedWrap pDW1{};
    
  • Secondly, the pDW1 is simply a DerivedWrap object. Therefore, no need for calling operator->. You need in short
    DerivedWrap pDW1;
    pDW1.print(); 
    
    The same applies to the pDW2. You need
    DerivedWrap pDW2(std::make_unique<Derived>(2));
    pDW2.print();
    
  • Last but not the least, the Base must-have virtual destructor for the defined behaviour. See more: When to use virtual destructors?

In short, you need

#include <iostream>
#include <memory>

class Base
{
public:
   virtual void print() = 0;
   virtual ~Base() = default;  // provide virtual destructor
};

class Derived /*final*/: public Base
{
public:
   // ... other code

   void print() override // recommended to override the virtual functions
   {
      std::cout << "int is " << i << std::endl;
   }
private:
   int i;
};

class DerivedWrap /* final */
{
public:
   // ...other code

   void print()
   {
      _pBase->print();
   }

private:
   std::unique_ptr<Base> _pBase;
};

int main()
{
   DerivedWrap pDW1; // or DerivedWrap pDW1{};
   pDW1.print();

   DerivedWrap pDW2{ std::make_unique<Derived>(2) };
   pDW2.print();
}

As a side note, please do not practice with using namespace std;

JeJo
  • 30,635
  • 6
  • 49
  • 88
4

You have some typos there, it should be:

int main()
{
  DerivedWrap pDW1; // object instantiation, no () needed
  pDW1.print(); //no dereferencing required

  DerivedWrap pDW2(make_unique<Derived>(2));
  pDW2.print(); // again, no dereference required

  return 0;
}

One other note, for polymorphic objects you're going to need a virtual destructor in your base class.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
2

This has nothing to do with polymorphism, virtual functions or smart pointers.

You just made two little typographical mistakes:

  1. DerivedWrap pDW1(); declares a function. Remove the ().
  2. -> dereferences pointers, but neither pDW1 nor pDW2 is a function. Use . instead.
Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35