2

My aim is to be able to create an object with a different kind of member object of from same class family; in Java it seems like this:

public class Interface {
    public void test();
}

public class MyImpl1 implements Interface {
    @Override
    public void test() {System.out.println("I am impl 1");}
}

public class MyImpl2 implements Interface {
    @Override
    public void test() {System.out.println("I am impl 2");}
}

public class A {
    public A(Interface myinter) {
        _myinter = myinter;
    }

    Interface _myinter;
}

So that I can create an object with different implementation:

A a(new MyImpl1());

or

A a(new MyImpl2());

(Sorry if there is syntax error in this botched code, it is just to explain what I want)

So, in C++ I think I would implement this with smart pointer to benefit from RAII. Thus, I wrote this code:

#include <iostream>
#include <memory>

using namespace std;

struct Interf {
    virtual void test() {cout << "I am Interf" << endl;}
};

struct A {
    A(std::unique_ptr<Interf> e) : _e(std::move(e)) {}

    std::unique_ptr<Interf> _e;

    void test() {_e->test();}
};

struct Impl : public Interf {
    void test() {cout << "I am Impl;" << endl;}
};

int main()
{
    std::unique_ptr<Interf> b(new Impl);

    A a(std::move(b));

    a.test();

    cout << "fine!" << endl;
    return 0;
}
  • It seems to me working. But, is this a correct way to implement it, or there are errores, or better practices?

  • Also, in this code, I am not sure if I needed to use std::move twice. Is this the correct way to pass unique_ptr to constructor?

  • Another thing I did not understand is why this code does not compile if I remove _e(std::move(e)) from memberwise init list and put inside the constructor; some one please could also explain what is going on here?

.

struct A {
    A(std::unique_ptr<Interf> e) {
        _e(std::move(e));
    }
    ...
};
Mert Mertce
  • 1,614
  • 3
  • 21
  • 32
  • possible duplicate of [How do I pass a unique\_ptr argument to a constructor or a function?](http://stackoverflow.com/questions/8114276/how-do-i-pass-a-unique-ptr-argument-to-a-constructor-or-a-function) – jwueller Aug 10 '15 at 09:24
  • This is a fine question, do note however that the [codereview.se] stack is specifically meant for working code in need of a double-check. StackOverflow here rather deals with non-woking code. – Quentin Aug 10 '15 at 09:35
  • 3
    "In need of a double-check" is maybe an unlucky formulation. Code Review requires code to be working to the best of your knowledge. Basically you should be confident your code works as intended in all cases. A double-check should happen **before** posting to CR. – Vogel612 Aug 10 '15 at 09:37
  • @Quentin Mm yes right. But also here there are lots of "best practice", "how does it work" questions, and also they are those with most upvotes. – Mert Mertce Aug 10 '15 at 09:38
  • 1
    @Mert Only because people like them. But that is irrelevant. They are still off-topic. – Lightness Races in Orbit Aug 10 '15 at 09:42
  • @Vogel612 it is, thanks for the clarification. Mert : Just a heads up because you're going that way. I personally think this question is fine here. – Quentin Aug 10 '15 at 09:47
  • @Quentin Yes, I saw your intent and told that you are right. Though I doubt why SO persists on this if lots of users like that and practically disregards it. – Mert Mertce Aug 10 '15 at 09:56
  • 1
    @MertMertce human bias, or historical reasons (CodeReview is much younger than SO). Also because migrating questions between stacks is inconvenient, as users don't necessarily have a matching account on the other side, so it's reserved to completely off-topic questions. – Quentin Aug 10 '15 at 10:03
  • Java exemple need edition as implementations of interface must extend it. – Jean-Baptiste Yunès Aug 10 '15 at 10:24
  • @Jean-BaptisteYunès done! Although I didn't mean it. – Mert Mertce Aug 10 '15 at 10:28
  • 1
    As a side note: it is a good practice to use `override` (so `void test() override {std::cout << "I am Impl;" << std::endl;}`), and avoid `using namespace std;`. – Jarod42 Aug 10 '15 at 10:48
  • @Jarod42 yeah, I like to use Override. I didn't know that in c++ existed. Thanks. – Mert Mertce Aug 10 '15 at 10:58
  • @MertMertce: It exists since C++11. – Jarod42 Aug 10 '15 at 11:01

1 Answers1

2

There are three std::unique_ptrs that pass your Interf around :

  • b, the local variable in main();
  • e, the parameter of A's constructor;
  • _e, the member of the constructed A instance.

It makes complete sense that moving the Interf instance across three different pointers needs two successive std::move() operations (b to e, then e to _e).

Slightly off-topic : C++14 encourages the use of std::make_unique. This is C++11 though.

Your code is absolutely fine :)

Edit :

Member variables are initialized in the member-initialization list only. In the constructor's body, _e(std::move(e)); means to call _e's operator () as if it was a functor.

Assigning to _e should be done with _e = std::move(e);, although it's always better to simply initialize it directly.

Community
  • 1
  • 1
Quentin
  • 62,093
  • 7
  • 131
  • 191