Reputation: 1097
I am trying to encapsulate details of the Engine implementation class. To do that I am returning std::unique_ptr
of abstract class (IEngine
in my case) instead of Engine
. But I could not do that due to the compile error. I could return raw reference and it works but is that possible with unique_ptr
? Thanks in advance.
class IEngine
{
public:
virtual ~IEngine() = default;
virtual void Start() = 0;
};
class Engine : public IEngine
{
public:
void Start() override {}
};
class Car
{
std::unique_ptr<Engine> m_engine;
public:
std::unique_ptr<IEngine>& Get() { return m_engine; } // Here is compile error
};
int main()
{
Car lambo;
}
Upvotes: 0
Views: 202
Reputation: 122575
I am trying to encapsulate details of the Engine implementation class.
Returning a non-const reference to a private member is rarely the right thing to do. In any case it is the opposite of data encapsulation. Once the caller has the reference they can do with it whatever they like. Returning a non const reference makes sense for convenience access methods like for example std::vector::operator[]
. The purpose of std::vector::operator[]
is not to hide the element from the caller. There are other ways to get your hands on it. Rather std::vector::operator[]
is to make it more convenient to access elements. Encapsulation it is not.
It is also not clear why you want to return a unique_ptr
from Get
. When no transfer of ownership is desired no smart pointer needs to be returned.
I could return raw reference
Yes, thats perfectly fine:
#include <memory>
class IEngine
{
public:
virtual ~IEngine() = default;
virtual void Start() = 0;
};
class Engine : public IEngine
{
public:
void Start() override {}
};
class Car
{
std::unique_ptr<Engine> m_engine;
public:
const IEngine& Get() { return *m_engine; } // Here is compile error
};
int main()
{
Car lambo;
}
Upvotes: 1
Reputation: 62779
std::unique_ptr<IEngine>
is a different type to std::unique_ptr<Engine>
, so you are asking to return a reference to a temporary object.
std::unique_ptr
uniquely owns the object it points to, so even if you removed the reference, it would be incorrect to create a std::unique_ptr<IEngine>
from the existing std::unique_ptr<Engine>
that you presumably want to leave unchanged.
You shouldn't be exposing std::unique_ptr
here. I'm not really sure you should be exposing IEngine
here. I'm also confused as to why you need the concrete Engine
type in Car
, but the outside world needs mutable access to a pointer to IEngine
.
I would instead expect something like:
class Car
{
std::unique_ptr<IEngine> m_engine;
public:
void TurnIgnition() { m_engine->Start(); }
};
Upvotes: 1