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();
}
-
1Generally speaking, rvalue references are an implementation detail, and class users should almost never be exposed to them.fredoverflow– fredoverflow2011年12月04日 10:12:30 +00:00Commented Dec 4, 2011 at 10:12
1 Answer 1
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.
-
Which part is undefined? Return a Rvalue from a function or capture a Rvalue from a return object?authchir– authchir2011年12月03日 16:14:56 +00:00Commented 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.DeadMG– DeadMG2011年12月03日 16:19:43 +00:00Commented Dec 3, 2011 at 16:19
-
I've just add an update version in the initial question. What do you think of it?authchir– authchir2011年12月03日 17:42:41 +00:00Commented 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.DeadMG– DeadMG2011年12月03日 20:49:35 +00:00Commented Dec 3, 2011 at 20:49
-
1@Coder: He returned a reference to a local variable. That's UB.DeadMG– DeadMG2011年12月11日 15:41:21 +00:00Commented Dec 11, 2011 at 15:41