1

Problem summary
I don't know how to create an object of a derived class with the new-operator through a function (not a constructor), and have a base class pointer point to it.

Setup
I have an abstract base class and a derived class in my project:

class Base
{
    // stuff
};

class Derived : public Base
{
    //stuff
    //constructor:
    Derived(args);
};

I also have function that returns a Derived object.

Derived func(args);

At some point, I declare a base class pointer

Base* ptr = { nullptr };

and I want it to point to a Derived object later-on.

What I want
I want to create a Derived object using func, and be able to access it through the pointer ptr later in the code.

What I did so far
I know that it works to use the derived class's constructor

ptr = new Derived(args);

or simply its default constructor, if it exists

ptr = new Derived;

However, I have good reasons why I cannot use the constructor in my case, since the configuration of the derived object is more complicated. In this case I want to create this object with the function func.

I know that this,

ptr = new func(args);

does not work, since new expects a type. How can I achieve a behavior like this?

Thanks in advance for any advice and helpful replies.

Note: I'm using new since I need to access the Derived object also outside the scope of its creation.

14
  • 2
    Can you rewrite func such that it returns Derived* instead of Derived? If so, don't forget to make destructor of Base virtual. You can also write Derived d = func(args); ptr = &Derived;, just it's kind-of fragile, since d must then outlive any dereferencing of ptr. Commented May 20, 2020 at 8:29
  • Thanks for the prompt reply. The problem is indeed that d will not outlive the pointer, which is why I used new so far. Commented May 20, 2020 at 8:35
  • 1
    Return a pointer from func might be the best option, but if you cannot modify func then ptr = new Derived(func(args)) might work. Commented May 20, 2020 at 8:42
  • 1
    @Mestkon This might be worth posting as an answer. Commented May 20, 2020 at 8:44
  • 1
    @user157765 Either copy costructor or move constructor Commented May 20, 2020 at 8:46

4 Answers 4

1

Return a pointer from func might be the best option, but if you cannot modify func then ptr = new Derived(func(args)) might work. This requires that Derived has a copy constructor or a move constructor.

Sign up to request clarification or add additional context in comments.

Comments

1
Derived * func(args)
{
  Derived *p = new Derived();
  // do your custom stuff:
  p->x = args->i;
  p->y = 3;

  // return the pointer
  return p;
}

// ...

ptr = func(args);

Dont forget to delete ptr later. To be able to call the destructor of Derived, using the pointer to Base later, you have to make the destructor virtual.

class Base
{
  // ...
  virtual ~Base();
};

1 Comment

I can modify func, so this might work. It is not what I had in mind for the return value of the function, but I will give it a try.
1

Solution summary

First of all, thanks to everyone who responded. The advice came incredibly fast and was very helpful and instructive.

I don't know if this is against some convention, but since there were multiple very different solutions, I would like to summarize them. (If I should rather put this as an edit to the question, please let me know).

All three solutions should work, and I use solution 2 for now. However, I might switch to solution 3 after learning more about smart pointers.

Solution 1 - by Alex and Daniel Langr

[link to reply]

Changing the function func such that it returns a pointer.

Derived* func(args)
{
    Derived *p = new Derived();
    // do some complicated configuration
    return p;
}

Afterwards, I can use the function to directly define the pointer ptr.

ptr = func(args);

Alex also made some important remarks about how to delete the ptr later.

While this works very well, I chose not to follow this path, since I would like to avoid changing the return value of func.

Solution 2 - by Mestkorn

[link to reply]

Use the copy constructor.

This is maybe the simplest solution. By using the copy constructor, I can simply write

    ptr = new Derived( func(args) );

While this requires a copy/move constructor, it worked perfectly well with the default copy constructor in my project. I didn't have to implement anything new. This is the solution I have in my code for now.

Solution 3 - by DNT

[link to reply]

Use smart pointers, more specifically a shared_ptr (Either std::shared_ptr or boost::shared_ptr.) This concept is completely new to me. Thanks for that!

I will learn more about this and might switch to this option, since it sounds like a cleaner solution. If I understand correctly, the advantage over the other two solutions is that I don't have to think about memory leakage or deleting the pointer.
Once I figured this out properly, I will come back and extend this summary.

Comments

0

You might want to look into writing your func as

template<class T, class TA> boost::shared_ptr<T> func(TA args) { return boost::make_shared<T>(args); }

or

template<class T, class TA> std::shared_ptr<T> func(TA args) { return std::make_shared<T>(args); }

if you want to generalize it for any compatible class and argument types. You may also want to typedef the shared pointer for better readability. The shared pointer will also take care of object lifetime.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.