2

I have the following situation where I have a base class and multiple polymorphics derived classes:

#include <iostream>

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

class Derived1 : public Base {
    public:
        virtual void foo() { std::cout << "Derived1::foo()\n"; };
};

class Derived2 : public Base {
    public:
        virtual void foo() { std::cout << "Derived2::foo()\n"; };
};

I want to make sure that my class users will always use the base class to use object of this hierachy. I got the idea to provide a factory methods returning the good object. From now, the methods look like this:

Base&& make_base(int i) {
    if(i == 1)
        return Derived1();
    else
        return Derived2();
}

The client can then use it that way:

int main() {
    Base&& b = make_base(1);
    b.foo();
}

Assuming C++03 compatibility is not needed, is this considered a good practice?

Edit

AS DeadMG pointed out, my initial make_base has undefined behaviour. If I can't require clients to only use Base class, I wish I could recommend it. Is this kind of factory a better idea?

#include <type_traits>
#include <string>

template <class Derived>
Derived make_base() {
    static_assert(
        std::is_base_of<Base, Derived>::value,
        "'Derived' must derived from 'Base'.");

    // Default behaviour
    return Derived();
}

template <>
Derived2 make_base<Derived2>() {
    // Specialise behaviour
    // Do something
    return Derived2();
}

int main() {
    auto b = make_base<std::string>(); // Error, 'Derived' must derived from 'Base'.
    Base&& b1 = make_base<Derived1>(); // call make_base()
    Base&& b2 = make_base<Derived2>(); // call make_base<Derived2>()
    b1.foo();
    b2.foo();
}
1
  • 1
    Generally speaking, rvalue references are an implementation detail, and class users should almost never be exposed to them. Commented Dec 4, 2011 at 10:12

1 Answer 1

3

No, this is undefined behaviour. The temporary variable will not have it's lifetime extended.

In addition, I'd say it's a code smell to not offer Derived1 and Derived2. Only accessing through the base class is something you only do if the derived class cannot be known at compile-time.

6
  • Which part is undefined? Return a Rvalue from a function or capture a Rvalue from a return object? Commented Dec 3, 2011 at 16:14
  • 4
    @authchir: The part where you return a reference to a temporary object. That is and always has been UB. Commented Dec 3, 2011 at 16:19
  • I've just add an update version in the initial question. What do you think of it? Commented Dec 3, 2011 at 17:42
  • @authchir: It's not UB anymore. But your fundamental design is still a poor idea- why restrict users from using their intended derived class directly? For example, you now enforce a static lifetime, whereas a user may prefer a dynamic lifetime. Commented Dec 3, 2011 at 20:49
  • 1
    @Coder: He returned a reference to a local variable. That's UB. Commented Dec 11, 2011 at 15:41

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.