I am trying to implement something similar to the Python with statement in C++. As I plan to use it mainly with Qt-OpenGL the methods are called bind and release (in Python __enter__, __exit__).
Code I came up with:
header:
#include <iostream>
#include <vector>
class With
{
public:
class A
{
public:
virtual ~A() { }
};
template <typename T>
class B : public A
{
public:
B(T& _t) : t(_t)
{
t.bind();
}
virtual ~B()
{
t.release();
}
T& t;
};
template <typename... Args>
With(Args&... args)
{
set(args...);
}
~With();
template <typename T, typename... Args>
void set(T& t, Args&... args)
{
set(t);
set(args...);
}
template <typename T>
void set(T& t)
{
a.push_back(dynamic_cast<A*>(new B<T>(t)));
}
std::vector<A*> a;
};
cpp:
With::~With()
{
for (auto it = a.begin(); it != a.end(); ++it)
{
delete *it;
}
}
Usage:
class X
{
public:
void bind() { std::cout << "bind x" << std::endl; }
void release() { std::cout << "release x" << std::endl; }
};
class Y
{
public:
void bind() { std::cout << "bind y" << std::endl; }
void release() { std::cout << "release y" << std::endl; }
};
int main()
{
X y;
Y y;
std::cout << "start" << std::endl;
{
With w(x, y);
std::cout << "with" << std::endl;
}
std::cout << "done" << std::endl;
return 0;
}
Questions:
Needing class A and class B feels a bit clumsy. Is there a better alternative?
Are there any draw backs in using && instead of &? It would make the usage of tempory objects possible (e.g. With w(X(), y);)
The with statement is a way to do in python what is already the normal thing in C++. It is called RAII: Resource acquisition is initialization.
In python, when a class object is created, the __init__ method is called (but this is not a strict guarantee). The __del__ method is called by the garbage collector at some point after the object is no longer in use, but it is not deterministic.
In C++ the destructor is called at a well defined point so there is no need for with.
I suggest you just use something like class B (no need for class A or With).
template <typename T>
class B {
public:
B(T& t) : m_t(t){
m_t.bind();
}
~B() {
m_t.release();
}
T& m_t;
}
use it like this:
{
B<X> bound_x(x); // x.bind is called
B<Y> bound_y(y); // y.bind is called
// use x and y here
} // bound_x and bound_y is destroyed here
// so x.release and y.release is called
It ships with the language, and it's called RAII.
struct X {
X() { std::cout << "bind\n"; }
~X() { std::cout << "release\n"; }
};
int main() {
X x;
}
One possible solution:
template <typename T>
void with(T *t, std::function<void ()> fn) {
t->bind();
fn();
t->unbind();
}
Usage:
with(object, []() {
// object bound
});
While I agree with the answers here that RAII is the C++ way to manage resource life-cycles, I personally find RAII not robust enough to handle all scenarios. I find that the constructor/destructor paradigm is good enough for memory resource management. For other resources (eg. file descriptors, sockets, timers etc) using an explicit resource management block provides more robustness. My reasoning is as follows -
Assume your resource is a file descriptor. You want to close it in the destructor but some IO error occurred. What do you do? Throwing an exception from a destructor is a very bad choice. Just ignoring the error is probably just as bad. For situations like this other languages give resource block mechanism to decouple resource management from object lifecycle.
C++ already faces this issue in its standard library. The std::mutex lock and unlock methods are essentially resource holders. However the lifecycle of std::mutex cannot be tied to lock/unlock. So we have a wrapper class std::lock_guard solely for lock/unlock RAII purpose. While an elegant solution, the problem is this lacks generality. Imagine every resource-management related class coming up with its own wrapper class. If we had a standard defined resource-management mechanism we could probably uniformly do this with a single wrapper template.
I hope this convinces RAII proponents that a standard specified resource-management model on top of RAII paradigm would be good.
Coming to the question about Python with clause: A very naive implementation would be something as follows:
// Standardised interface for resource managers.
template<typename T>
concept Withable = requires(T t) {
{ t.bind() } -> std::same_as<void>;
{ t.release() } -> std::same_as<void>;
};
// Universal wrapper for all resource managers.
template<Withable T>
struct WithWrapper {
T* ref_;
WithWrapper(T& obj)
: ref_{&obj}
{ ref_->bind(); }
~WithWrapper() { ref_->release(); }
T& get() { return *ref_; }
};
// In case we want the with keyword.
#define with(...) if (__VA_ARGS__; true)
Usage for your case would be -
// Making sure your types are compatible.
static_assert(Withable<X>);
static_assert(Withable<Y>);
// Using the with and wrapper.
int main() {
X y;
Y y;
// With my naive implementation it's not really possible to declare two
// separate types in same initialisation block. However even with two
// "with"s, the execution behaviour is extacly the same as Python.
with (auto xw = WithWrapper(x)) { with (auto yw = WithWrapper(y)) {
// Do something with xw and yw ...
} }
}
Related
Inversion of control is a value-proof technique which is used to modularize a system and decouple the components from each other.
Low coupling is always an advantage: it simplifies automatic testing of the components and makes the code better conforming to single responsibility principle.
Among the ways to declare a dependency to another class (service locator, property injection calling a public method / setting a public property...), the constructor injection seems the best approach.
Though it's probably the most difficult one (at least from the listed three) to implement, it comes with significant advantages:
all the dependencies are truly visible with constructor signature;
cyclic dependencies don't happen because of the well-defined order of instantiation.
What are the pros / cons of the many choices C++ offers to perform the injection via constructor?
Instance copyable class
class object
{
public:
object(dependency d) : dep_(d) {}
private:
dependency dep_;
};
Only works in case dependency class is completely stateless, i.e. doesn't have any members. Practically, this rarely happens because dependency class may store its own dependency.
Raw pointer
class object
{
public:
object(dependency *d) : dep_(d)
{
if (d == nullptr)
throw std::exception("null dependency");
}
private:
dependency *dep_;
};
This works like true injection. We're required to check the passed pointer for nullptr value.
object class does not own dependency class, thus it's the responsibility of calling code to make sure the object is destroyed before the dependency object.
In real application, it's sometimes very difficult to validate.
Reference
#define DISALLOW_COPY_AND_ASSIGN(Class) \
Class(const Class &) = delete; \
Class &operator=(const Class &) = delete
class object
{
public:
object(dependency &d) : dep_(d) {}
DISALLOW_COPY_AND_ASSIGN(object);
private:
dependency &dep_;
};
The reference cannot be null, so it's a bit safer in this prospective.
However this approach brings additional constraints to object class: it has to be non-copyable since a reference cannot be copied. You have to either manually override assignment operator and copy constructor to stop from copying or inherit it from something like boost::noncopyable.
Like with raw pointer, the ownership constraint is in place. Calling code should provide the correct destruction order for both classes, otherwise the reference becomes invalid and application crashes with access violation.
If the dependency is a const reference:
class object
{
public:
object(const dependency &d) : dep_(d) {}
private:
const dependency &dep_;
};
you should pay attention to the fact that the object class accepts references to temporary objects:
dependency d;
object o1(d); // this is ok, but...
object o2(dependency()); // ... this is BAD.
Further details:
C++: non-temporary const reference
What are the advantages of boost::noncopyable for several approaches to prevent copying a class
Should I prefer pointers or references in member data?
Using reference as class members for dependencies
Smart pointer
class object
{
public:
object(std::shared_ptr<dependency> d) : dep_(d)
{
if (!d)
throw std::exception("null dependency");
}
private:
std::shared_ptr<dependency> dep_;
};
Similar to raw pointer but the ownership is controlled by smart pointer mechanism.
Still need to check for nullptr in the constructor body.
The major advantage is the dependency object lifetime control: there is no need for the calling application to properly control the destruction order (but consider that you need to be very careful when designing your APIs with std::shared_ptr).
Once the dependency class is no longer used it's automatically destroyed by shared_ptr destructor.
There are cases when shared_ptr owned objects are not destroyed (so called cyclic references). However, with constructor injection, cyclic dependencies aren't possible due to the specific well-defined order of construction.
This works of course if no other injection methods are used across the application.
A smart pointer has a small overhead but it isn't a real problem in the majority of cases.
Further details:
Disadvantages of shared_ptr
GotW #91: Smart Pointer Parameters
This is an old question but for me this is a hot topic because I've found automatic dependency injection sorceries in all web the framewrks I could hear of, they are often built with introspection shananigans and I always have great time discovering their implementations. But I couldn't find an easy way to do the same in C++.
The service locator approach can solve the problem pretty well indeed but declaring the dependencies in the constructor and getting rid of such pattern in between seems cleaner and more flexible to use because it is easier to instantiate your classes passing different instances of your services.
But the service locator approach can also handle cyclic dependencies because they can be lazily picked, and sometimes cyclic dependencies can happen (maybe in bad code only).
Unfortunately I haven't figured out way to detect the types of the arguments in constructors and automatically inject instances of such types, yet.
Anyway I want to share the best solution I found so far to automatically inject deendencies in classes. It is similar to a service locator that handles its service as a singleton with smart pointers and can be used for dependency injection, but it have to be revised to allow two classes that have some dependencies in common to get different instances of the same type.
template<typename T>
struct di_explicit
{
static std::shared_ptr<T> ptr;
virtual ~di_explicit()
{
if(di_explicit<T>::ptr.use_count() == 1) {
reset();
}
}
virtual std::shared_ptr<T> get()
{
return di_explicit<T>::ptr;
}
static void reset()
{
di_explicit<T>::ptr.reset();
}
static void swap(std::shared_ptr<T> arg)
{
arg.swap(di_explicit<T>::ptr);
}
static void emplace(auto && ... args)
{
swap(std::make_shared<T>(std::forward(args) ...));
}
static void emplace_if_not_exists(auto && ... args)
{
if(!di_explicit<T>::ptr) {
emplace(std::forward(args) ...);
}
}
};
template<typename T>
std::shared_ptr<T> di_explicit<T>::ptr {};
template<typename T>
struct di : di_explicit<T>
{
di(auto && ... args)
{
di_explicit<T>::emplace_if_not_exists(std::forward(args) ...);
}
};
template<typename T>
struct di_lazy : di_explicit<T>
{
auto get(auto && ... args)
{
di_explicit<T>::emplace_if_not_exists(std::forward(args) ...);
return di_explicit<T>::ptr;
}
};
The ideas behind the above snippet are:
It is a logic wrapper that handles the memory of another class, such wrapper is able to automatically create an instance of the managed class and pass the reference as a singleton when requested, the memory is automatically deallocated when there are no more reference to the managed object.
It is possible to use a specific instance of the managed class (or a subtype) so that the user can declare a dependency to an interface of the needed service and instanciate the concrete dependency when the program is running or a mock during tests.
In case of circular dependency there is a way to lazily instanciate the needed dependency.
The basic logic is coded in the base class di_explicit<T> that uses a static shared_ptr<T> to make the singletons, and a destructor that resets the shared pointer when the last reference left is the static one (stored in di_explicit<T>).
The struct di : di_explicit<T> retrive the dependency in its constructor while di_lazy : di_explicit<T> only does it when the dependency is requested (in the get() method).
The following is an example (non lazy) with a mock.
namespace {
struct dependency {
virtual void do_something() {
std::cout << "doing something" << std::endl;
}
};
struct mock : dependency {
using dependency::do_something;
void do_something() {
std::cout << "mocking something" << std::endl;
}
};
struct srv {
di<dependency> dep;
void do_stuff() {
std::cout << "doing stuff" << std::endl;
return dep.get()->do_something();
}
};
int test = [](){
// the classes are not instanciated yet
std::cout << "ptr exists " << !!di<srv>::ptr << std::endl;
{
// the classes instanciated here
di<srv> s;
s.get()->do_stuff();
std::cout << "ptr exists " << !!di<srv>::ptr << std::endl;
} // <- the instances are destroyed here
std::cout << "ptr exists " << !!di<srv>::ptr << std::endl;
{
// use a mock instance
di_explicit<dependency>::swap(std::make_shared<mock>());
di<srv>{}.get()->do_stuff();
} // <- the mock is destroyed here too
std::cout << "ptr exists " << !!(di<dependency>::ptr) << std::endl;
return 0;
}();
}
The following is an example with circular references and di_lazy.
namespace {
struct dep_2;
struct dep_3;
struct dep_1 {
di_lazy<dep_2> dep;
void do_something();
};
struct dep_2 {
di_lazy<dep_3> dep;
void do_something();
};
struct dep_3 {
di_lazy<dep_1> dep;
void do_something() {
std::cout << "dep_3 do_something" << std::endl;
dep.get()->do_something();
}
virtual void do_something_else() {
std::cout << "dep_3 do_something_else" << std::endl;
}
};
void dep_1::do_something() {
std::cout << "dep_1 do_something" << std::endl;
dep.get()->do_something();
}
void dep_2::do_something() {
std::cout << "dep_2 do_something" << std::endl;
dep.get()->do_something_else();
}
struct srv_2 {
di<dep_3> dep;
void do_something() {
std::cout << "srv_2 do_something" << std::endl;
return dep.get()->do_something();
}
};
int result = [](){
{
// neither the dependencies or the service are requested yet
di_lazy<srv_2> wrapper{};
// here the service is requested
auto s = wrapper.get();
// dependencies are requested inside this function
s->do_something();
}
{
struct mock_dep_3 : dep_3 {
virtual void do_something_else() {
std::cout << "dep_3 do_something_else MOCKED!" << std::endl;
}
};
// a mock can be used with di_lazy as well
di_explicit<dep_3>::swap(std::make_shared<mock_dep_3>());
di<srv_2>{}.get()->do_something();
}
return 0;
}();
}
I know there is room for improvements (any sugestion are appreciated), I hope you find it useful
EDIT
I found a sligly better way to do the same but this time extending the std::shared_ptr class itself.
It is still some kind of service locator but with the following snippet is also possible to pass shared pointers as arguments in your constructors
template<typename T>
class di : public std::shared_ptr<T>
{
static std::shared_ptr<T> ptr;
public:
static void reset()
{
di<T>::ptr.reset();
}
static di<T> replace(std::shared_ptr<T> ptr)
{
di<T>::ptr = ptr;
return di<T>::ptr;
}
template<typename ... args_t>
static di<T> emplace(args_t && ... args)
{
return di<T>::replace(std::make_shared<T>(
std::forward<args_t>(args) ...
));
}
static di<T> instance()
{
return di<T>::ptr;
}
~di()
{
if(this->is_linked() && di<T>::ptr.use_count() <= 2){
di<T>::ptr.reset();
}
}
bool is_linked()
{
return *this && di<T>::ptr.get() == this->get();
}
template<typename ... args_t>
di(args_t && ... ptr) : std::shared_ptr<T>(std::forward<args_t>(ptr) ...)
{}
};
template<typename T>
std::shared_ptr<T> di<T>::ptr {};
With this class you can pass the instance of some service to another using constructor
ie
struct logger_interface
{
virtual void log(std::string) = 0;
virtual ~logger_interface() = default;
};
struct some_service_interface
{
virtual void serve() = 0;
virtual ~some_service_interface() = default;
};
struct logger_with_id : logger_interface
{
static int counter;
int id = ++counter;
void log(std::string s) {
std::cout << id << ") " << s << std::endl;
}
};
int logger_with_id::counter = 0;
struct some_service : some_service_interface
{
di<logger_interface> logger;
some_service(
di<logger_interface> logger = di<logger_interface>::instance()
) :
logger(logger)
{}
void serve() {
logger->log("serving...");
}
};
int app = []() {
di<logger_interface>::replace(di<logger_with_id>::emplace());
di<some_service_interface>::replace(di<some_service>::emplace());
std::cout << "running app"<< std::endl;
di<logger_interface>::instance()->log("app");
di<some_service_interface>::instance()->serve();
std::cout << std::endl;
return 0;
}();
Will print
running app
1) app
1) serving...
And if you need you can override the dependency for some service
struct decorated_logger : logger_interface {
di<logger_interface> logger;
decorated_logger(
di<logger_interface> logger = di<logger_interface>::instance()
) :
logger(logger)
{}
void log(std::string s) {
logger->log("decorating...");
logger->log(s);
}
};
int app_with_custom_logger_on_service = [](
di<logger_interface> logger,
di<some_service_interface> service
) {
std::cout << "running app_with_custom_logger_on_service"<< std::endl;
logger->log("app");
service->serve();
std::cout << std::endl;
return 0;
}(
di<logger_interface>::replace(std::make_shared<logger_with_id>()),
di<some_service_interface>::replace(std::make_shared<some_service>(
std::make_shared<decorated_logger>(std::make_shared<logger_with_id>())
))
);
Will print
running app_with_custom_logger_on_service
2) app
3) decorating...
3) serving...
This can also be used for tests
struct mock_logger : logger_interface {
void log(std::string) {
std::cout << "mock_logger" << std::endl;
}
};
struct mock_some_service : some_service_interface {
void serve() {
std::cout << "mock_some_service" << std::endl;
}
};
int test = [](
di<logger_interface> logger,
di<some_service_interface> service
) {
std::cout << "running test"<< std::endl;
logger->log("app");
service->serve();
std::cout << std::endl;
return 0;
}(
di<logger_interface>::replace(std::make_shared<mock_logger>()),
di<some_service_interface>::replace(std::make_shared<mock_some_service>())
);
Will print
running test
mock_logger
mock_some_service
I made a gist for this example, you can run it on wandbox with clang
I have a scope guard like class (this is the simplified test case):
template<void(*close)()>
struct Guard1
{
template<typename O>
Guard1(O open) { open(); }
~Guard1() { close(); }
};
void close() { std::cout << "close g1\n"; }
int main()
{
Guard1<close> g1 = [](){ std::cout << "open g1\n"; };
}
I modified it such that the close expression can also be given as a lambda:
class Guard2
{
std::function<void()> close;
public:
template<typename O, typename C>
Guard2(O open, C close) : close(close)
{
open();
}
~Guard2() { close(); }
};
int main()
{
Guard2 g2(
[](){ std::cout << "open g2\n"; },
[](){ std::cout << "close g2\n"; });
}
However I had to introduce an extra field const std::function<void()>& close; to pass the lambda from the constructor to the destructor.
Is there a way to avoid this extra field while still keeping the lambda (and a nice syntax when used as well)?
Since you want to use it only as ScopeGuard - then you can be sure that const reference or rvalue reference to your close() are valid. You need a member or base class as in other answer - but this is not very big difference. But you can have it as rvalue reference to your lambda, not to std::function which is of quite big performance cost:
template <class Close>
class ScopeGuard {
public:
template <typename Open>
ScopeGuard(Open&& open, Close&& close)
: close(std::forward<Close>(close))
{
open();
}
ScopeGuard(ScopeGuard&& other) : close(std::move(other.close))
{}
~ScopeGuard()
{
close();
}
private:
Close&& close;
};
To make it easier to use - have this make function:
template <class Open, class Close>
auto makeScopeGuard(Open&& open, Close&& close)
{
return ScopeGuard<Close>(std::forward<Open>(open),
std::forward<Close>(close));
}
And usage:
#include <iostream>
using namespace std;
int main()
{
int i = 0;
auto scope = makeScopeGuard([&i]{cout << "Open " << i++ << "\n";},
[&i]{cout << "Close " << i++ << "\n";});
cout << "Body\n";
}
Output:
Open 0
Body
Close 1
I verified it works for gcc and clang, C++14 without errors/warnings.
It's generally not possible. Unlike a function pointer, a lambda can capture and therefore contain run-time state. True, your lambda does not, and therefore can be converted to a function pointer, but that doesn't make it a template argument.
If you can accept a bit of cheating: stuff the lambda into a base class instead of a field:
#include <iostream>
template<typename Base>
struct Guard1 : public Base
{
template<typename O>
Guard1(O open, Base base ) : Base(base) { open(); }
Guard1(Guard1 const& rhs) : Base(static_cast<Base const&>(rhs)) { }
~Guard1() { (*this)(); }
};
template<typename O, typename C>
Guard1<C> makeGuard(O o, C c) { return Guard1<C>(o,c); }
int main()
{
auto g1 = makeGuard([](){ std::cout << "open g1\n"; },
[](){ std::cout << "close g1\n"; } );
}
Is there a way to avoid this extra field while still keeping the lambda (and a nice syntax when used as well)?
Yes: If you observe, there is nothing to be gained by passing the open function to your scope guard (therefore the Single Responsibility Principle states you should not have it there).
You should also pass the function as a runtime parameter, not a template parameter. This will allow for more natural syntax in client code.
You should make the type independent on the template type. This will also make for more natural syntax in client code.
You should ensure the destructor does not throw.
class Guard final
{
public:
Guard1(std::function<void()> at_scope_exit)
: f_(std::move(at_scope_exit))
{
}
~Guard1() noexcept { try{ f_(); } catch(...) {} }
private:
std::function<void()> f_;
};
Your client code should then look like this:
int x()
{
operation.begin_transaction();
Guard commit{ [&operation](){ operation.commit_transaction(); } };
// do things & stuff here
}
Maybe you can use the answer of this question.
Hope I am not wrong, but if it was possible to use the constructor's pointer, you could pass it to type_traits (look at the first answer in that question), and get the second argument which would be close function, and then you could alias it.
Since it is not possible to get the constructor's pointer, maybe you can use an other member function to initialize your object ?
I have a kind of object registry where objects can be registered. This should be done in the initialization phase. E.g.
class ObjectBase {
protected:
bool active;
public:
void activate() { active = true; }
};
template<typename T>
class Object : public ObjectBase {
T value;
};
class Registry {
public:
template<typename T>
static std::shared_ptr<Object<T>> registerObject() {
return std::make_shared<Object<T>>();
}
namespace {
std::shared_ptr< Object<int> > myObject = Registry::registerObject<int>();
}
Now I want the active value set at initialisation (and constructor parameters are not an option, as this is but one of many). What would be neat is if I were able to do the following:
namespace {
std::shared_ptr< Object<int> > myObject = Registry::registerObject<int>()->activate();
}
However I don't see a way for activate() to return a pointer of type Object (unless I make it a template as well and do a dynamic cast, however this seems ugly), lest so a shared pointer. Or is there some way? Alternatively, do any of you have a recommendation how to approach this task (i.e. register something and set a number of properties)?
EDIT:
Naming my class Object may have been unfortunate. As a practical example, think of Object as a property (holding an integer). Obviously there may be multiple integer properties. And imagine "active" as something akin to "should be backed up" / "should be synced with a remote process" / ...
template<typename T>
std::shared_ptr< Object<T> > RegisterAndActivate() {
std::shared_ptr< Object<T> > p = Registry::registerObject<T>();
p->activate();
return p;
}
namespace {
std::shared_ptr< Object<int> > myObject = RegisterAndActivate<int>();
}
What about freestanding function(s):
template <typename T>
std::shared_ptr<Object<T>> activate(std::shared_ptr<Object<T>> ptr) {
ptr->activate();
return ptr;
}
Then
auto x = activate(Registry::registerObject<int>());
Ok, here's what I came up with:
#include <iostream>
#include <tuple>
#include <memory>
struct Test {
bool a;
bool b;
Test() : a(false),b(false) {};
};
template<typename T, bool T::* ... props>
std::shared_ptr<T> activate(std::shared_ptr<T> inst) {
std::tie((inst.get()->*props)...) = std::make_tuple((props,true)...);
return inst;
}
int main()
{
auto t1 = activate<Test,&Test::a>(std::make_shared<Test>());
auto t2 = activate<Test,&Test::a,&Test::b>(std::make_shared<Test>());
std::cout << "t1: a = " << t1->a << ", b = " << t1->b << std::endl;
std::cout << "t2: a = " << t2->a << ", b = " << t2->b << std::endl;
}
Basically, whatever pointers to bool members you specify as template parameters, those are going to be set to true by the activate function. This way, you don't have to write many activate functions, but it is still a lot of writing because of all the Classname::classmember expressions. Working example here.
Consider the following class structure:-
class foo {
public:
int fun () {
cout << "in foo" << endl;
}
};
class bar_class1:public foo {
public:
int fun () {
cout << "in bar_class1" << endl;
}
};
class bar_class2:public foo {
public:
float fun () {
cout << "in bar_class2" << endl;
}
};
main () {
foo * foo_pointer = new bar_class1();
foo_pointer->fun();
}
The output of the above program is in foo. Is there a way, that using a pointer of type foo * which actually points to an object of type bar_class1 or bar_class2, we can call the fun function of the derived class instead of the base class? I am not able to make the fun function virtual in the base class foo since, then there is a return type conflict for function foo in the derived class bar_class2.
Here's my comments as an answer.
You cannot do that.
If that kind of polymorphism were possible, wouldn't that break horribly when code calls foo::fun (expecting an int) on an object whose actual type is bar_class2 and thus gets a float? Do you want to simply throw away type safety?
If you want different return types, sounds like you want a template. But you cannot use templates quite in the way that you want to use foo(). Static polymorphism (templates) and run time polymorphism (late binding) don't mix well. You need to redesign your oop structure.
If you absolutely hate type safety, you can sort of do this with void pointers. But for the love of Flying Spaghetti Monster, don't ever do this in c++. Please close your eyes before reading the following code to avoid exposure.
#include <iostream>
class foo {
public:
virtual void* fun() = 0;
virtual ~foo(){};
};
class bar_class1: public foo {
public:
void* fun() {
return &value;
}
private:
int value = 1;
};
class bar_class2: public foo {
public:
void* fun() {
return &value;
}
private:
float value = 1.1;
};
int main() {
foo* foo_pointer1 = new bar_class1();
foo* foo_pointer2 = new bar_class2();
// in c++ compiler must know the type of all objects during compilation
std::cout << *reinterpret_cast<int*>(foo_pointer1->fun()) << '\n';
std::cout << *reinterpret_cast<float*>(foo_pointer2->fun()) << '\n';
delete foo_pointer1;
delete foo_pointer2;
}
Perhaps similar to the existing answer, I really hope you realize changing your design is better than this mess, but I believe it's the best you're going to get. I force you to specify the return type at the callsite (e.g., someFoo->fun<int>()), since you're going to have to know it anyway, and dispatch based on that. Any funny business and you'll get an exception. Also keep in mind the performance of this is, I imagine, less than desirable.
#include <cassert>
#include <stdexcept>
#include <type_traits>
struct foo {
virtual ~foo() = default;
template<typename T, typename = typename std::enable_if<std::is_same<T, int>::value>::type, typename = void>
T fun();
template<typename T, typename = typename std::enable_if<std::is_same<T, float>::value>::type>
T fun();
};
struct bar_class1 : foo {
int fun() {
return 2;
}
};
struct bar_class2 : foo {
float fun() {
return 3.5f;
}
};
template<typename T, typename, typename Dummy>
T foo::fun() {
if (auto *p = dynamic_cast<bar_class1 *>(this)) {
return p->fun();
} else if (dynamic_cast<bar_class2 *>(this)) {
throw std::invalid_argument("Mismatching dynamic type.");
} else {
return 1;
}
}
template<typename T, typename>
T foo::fun() {
auto *p = dynamic_cast<bar_class2 *>(this);
if (dynamic_cast<bar_class1 *>(this) || !p) {
throw std::invalid_argument("Mismatching dynamic type.");
} else if (auto *p = dynamic_cast<bar_class2 *>(this)) {
return p->fun();
}
assert(false); //should never get here, but compiler doesn't know that
}
If you'd like the main function, I've written a complete sample.
To answer your question: No, late binding isn't possible without deciding the return type. ...at least not in a reasonable manner, see user2079303's great counter-example. But...
you may change your code (for example) into something like the following, using the keyword virtual and equalize the return type for instance to void:
class foo
{
public:
virtual void fun(std::ostream& out) {
out << "in foo" << std::endl;
}
};
so you can decide the output type later:
class intFoo: public foo
{
public:
void fun(std::ostream& out) {
// output an int
out << "in bar_class1. data: " << data << endl;
}
int data;
};
class floatFoo: public foo
{
public:
void fun(std::ostream& out) {
// output a float
out << "in bar_class2. data: " << data << endl;
}
float data;
};
For brevity, I double-use the output stream - now a parameter of the function fun() - function to demonstrate type-dependent portion of your derived class. In your application, the parameter will probably be of another, more useful type.
The function fun is not a virtual function since you didn't use the keyword "virtual" to decorate it. So, the compile will determine which function to call at compiling time. So, there is no way to tell the compiler to call another function because the compiler will use its static type, i.e. the variable definition type -- foo *.
Consider the following setup.
Base class:
class Thing {
int f1;
int f2;
Thing(NO_INIT) {}
Thing(int n1 = 0, int n2 = 0): f1(n1),f2(n2) {}
virtual ~Thing() {}
virtual void doAction1() {}
virtual const char* type_name() { return "Thing"; }
}
And derived classes that are different only by implementation of methods above:
class Summator {
Summator(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 += f2; }
virtual const char* type_name() override { return "Summator"; }
}
class Substractor {
Substractor(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 -= f2; }
virtual const char* type_name() override { return "Substractor"; }
}
The task I have requires ability to change class (VTBL in this case) of existing objects on the fly. This is known as dynamic subclassing if I am not mistaken.
So I came up with the following function:
// marker used in inplace CTORs
struct NO_INIT {};
template <typename TO_T>
inline TO_T* turn_thing_to(Thing* p)
{
return ::new(p) TO_T(NO_INIT());
}
that does just that - it uses inplace new to construct one object in place of another. Effectively this just changes vtbl pointer in objects. So this code works as expected:
Thing* thing = new Thing();
cout << thing->type_name() << endl; // "Thing"
turn_thing_to<Summator>(thing);
cout << thing->type_name() << endl; // "Summator"
turn_thing_to<Substractor>(thing);
cout << thing->type_name() << endl; // "Substractor"
The only major problems I have with this approach is that
a) each derived classes shall have special constructors like Thing(NO_INIT) {} that shall do precisely nothing. And b) if I will want to add members like std::string to the Thing they will not work - only types that have NO_INIT constructors by themselves are allowed as members of the Thing.
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ? I have a feeling that std::move semantic may help to solve 'b' somehow but not sure.
Here is the ideone of the code.
(Already answered at RSDN http://rsdn.ru/forum/cpp/5437990.1)
There is a tricky way:
struct Base
{
int x, y, z;
Base(int i) : x(i), y(i+i), z(i*i) {}
virtual void whoami() { printf("%p base %d %d %d\n", this, x, y, z); }
};
struct Derived : Base
{
Derived(Base&& b) : Base(b) {}
virtual void whoami() { printf("%p derived %d %d %d\n", this, x, y, z); }
};
int main()
{
Base b(3);
Base* p = &b;
b.whoami();
p->whoami();
assert(sizeof(Base)==sizeof(Derived));
Base t(std::move(b));
Derived* d = new(&b)Derived(std::move(t));
printf("-----\n");
b.whoami(); // the compiler still believes it is Base, and calls Base::whoami
p->whoami(); // here it calls virtual function, that is, Derived::whoami
d->whoami();
};
Of course, it's UB.
For your code, I'm not 100% sure it's valid according to the standard.
I think the usage of the placement new which doesn't initialize any member variables, so to preserve previous class state, is undefined behavior in C++. Imagine there is a debug placement new which will initialize all uninitialized member variable into 0xCC.
union is a better solution in this case. However, it does seem that you are implementing the strategy pattern. If so, please use the strategy pattern, which will make code a lot easier to understand & maintain.
Note: the virtual should be removed when using union.
Adding it is ill-formed as mentioned by Mehrdad, because introducing virtual function doesn't meet standard layout.
example
#include <iostream>
#include <string>
using namespace std;
class Thing {
int a;
public:
Thing(int v = 0): a (v) {}
const char * type_name(){ return "Thing"; }
int value() { return a; }
};
class OtherThing : public Thing {
public:
OtherThing(int v): Thing(v) {}
const char * type_name() { return "Other Thing"; }
};
union Something {
Something(int v) : t(v) {}
Thing t;
OtherThing ot;
};
int main() {
Something sth{42};
std::cout << sth.t.type_name() << "\n";
std::cout << sth.t.value() << "\n";
std::cout << sth.ot.type_name() << "\n";
std::cout << sth.ot.value() << "\n";
return 0;
}
As mentioned in the standard:
In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [ Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if an object of this standard-layout union type contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of standard-layout struct members; see 9.2. — end note ]
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ?
If you have fixed set of sub-classes then you may consider using algebraic data type like boost::variant. Store shared data separately and place all varying parts into variant.
Properties of this approach:
naturally works with fixed set of "sub-classes". (though, some kind of type-erased class can be placed into variant and set would become open)
dispatch is done via switch on small integral tag. Sizeof tag can be minimized to one char. If your "sub-classes" are empty - then there will be small additional overhead (depends on alignment), because boost::variant does not perform empty-base-optimization.
"Sub-classes" can have arbitrary internal data. Such data from different "sub-classes" will be placed in one aligned_storage.
You can make bunch of operations with "sub-class" using only one dispatch per batch, while in general case with virtual or indirect calls dispatch will be per-call. Also, calling method from inside "sub-class" will not have indirection, while with virtual calls you should play with final keyword to try to achieve this.
self to base shared data should be passed explicitly.
Ok, here is proof-of-concept:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
Output is:
Summator 12 7
Substractor 5 7
size: 2
LIVE DEMO on Coliru
Full Code (it uses some C++14 features, but can be mechanically converted into C++11):
#define BOOST_VARIANT_MINIMIZE_SIZE
#include <boost/variant.hpp>
#include <type_traits>
#include <functional>
#include <iostream>
#include <utility>
using namespace std;
/****************************************************************/
// Boost.Variant requires result_type:
template<typename T, typename F>
struct ResultType
{
mutable F f;
using result_type = T;
template<typename ...Args> T operator()(Args&& ...args) const
{
return f(forward<Args>(args)...);
}
};
template<typename T, typename F>
auto make_result_type(F &&f)
{
return ResultType<T, typename decay<F>::type>{forward<F>(f)};
}
/****************************************************************/
// Proof-of-Concept
template<typename Base, typename ...Ts>
struct SubVariant
{
Base shared_data;
boost::variant<Ts...> sub;
template<typename Visitor>
friend auto apply(Visitor visitor, SubVariant &operand)
{
using result_type = typename common_type
<
decltype( visitor(shared_data, declval<Ts&>()) )...
>::type;
return boost::apply_visitor(make_result_type<result_type>([&](auto &x)
{
return visitor(operand.shared_data, x);
}), operand.sub);
}
};
/****************************************************************/
// Demo:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
use return new(p) static_cast<TO_T&&>(*p);
Here is a good resource regarding move semantics: What are move semantics?
You simply can't legally "change" the class of an object in C++.
However if you mention why you need this, we might be able to suggest alternatives. I can think of these:
Do v-tables "manually". In other words, each object of a given class should have a pointer to a table of function pointers that describes the behavior of the class. To modify the behavior of this class of objects, you modify the function pointers. Pretty painful, but that's the whole point of v-tables: to abstract this away from you.
Use discriminated unions (variant, etc.) to nest objects of potentially different types inside the same kind of object. I'm not sure if this is the right approach for you though.
Do something implementation-specific. You can probably find the v-table formats online for whatever implementation you're using, but you're stepping into the realm of undefined behavior here so you're playing with fire. And it most likely won't work on another compiler.
You should be able to reuse data by separating it from your Thing class. Something like this:
template <class TData, class TBehaviourBase>
class StateStorageable {
struct StateStorage {
typedef typename std::aligned_storage<sizeof(TData), alignof(TData)>::type DataStorage;
DataStorage data_storage;
typedef typename std::aligned_storage<sizeof(TBehaviourBase), alignof(TBehaviourBase)>::type BehaviourStorage;
BehaviourStorage behaviour_storage;
static constexpr TData *data(TBehaviourBase * behaviour) {
return reinterpret_cast<TData *>(
reinterpret_cast<char *>(behaviour) -
(offsetof(StateStorage, behaviour_storage) -
offsetof(StateStorage, data_storage)));
}
};
public:
template <class ...Args>
static TBehaviourBase * create(Args&&... args) {
auto storage = ::new StateStorage;
::new(&storage->data_storage) TData(std::forward<Args>(args)...);
return ::new(&storage->behaviour_storage) TBehaviourBase;
}
static void destroy(TBehaviourBase * behaviour) {
auto storage = reinterpret_cast<StateStorage *>(
reinterpret_cast<char *>(behaviour) -
offsetof(StateStorage, behaviour_storage));
::delete storage;
}
protected:
StateStorageable() = default;
inline TData *data() {
return StateStorage::data(static_cast<TBehaviourBase *>(this));
}
};
struct Data {
int a;
};
class Thing : public StateStorageable<Data, Thing> {
public:
virtual const char * type_name(){ return "Thing"; }
virtual int value() { return data()->a; }
};
Data is guaranteed to be leaved intact when you change Thing to other type and offsets should be calculated at compile-time so performance shouldn't be affected.
With a propert set of static_assert's you should be able to ensure that all offsets are correct and there is enough storage for holding your types. Now you only need to change the way you create and destroy your Things.
int main() {
Thing * thing = Thing::create(Data{42});
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
turn_thing_to<OtherThing>(thing);
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
Thing::destroy(thing);
return 0;
}
There is still UB because of not reassigning thing which can be fixed by using result of turn_thing_to
int main() {
...
thing = turn_thing_to<OtherThing>(thing);
...
}
Here is one more solution
While it slightly less optimal (uses intermediate storage and CPU cycles to invoke moving ctors) it does not change semantic of original task.
#include <iostream>
#include <string>
#include <memory>
using namespace std;
struct A
{
int x;
std::string y;
A(int x, std::string y) : x(x), y(y) {}
A(A&& a) : x(std::move(a.x)), y(std::move(a.y)) {}
virtual const char* who() const { return "A"; }
void show() const { std::cout << (void const*)this << " " << who() << " " << x << " [" << y << "]" << std::endl; }
};
struct B : A
{
virtual const char* who() const { return "B"; }
B(A&& a) : A(std::move(a)) {}
};
template<class TO_T>
inline TO_T* turn_A_to(A* a) {
A temp(std::move(*a));
a->~A();
return new(a) B(std::move(temp));
}
int main()
{
A* pa = new A(123, "text");
pa->show(); // 0xbfbefa58 A 123 [text]
turn_A_to<B>(pa);
pa->show(); // 0xbfbefa58 B 123 [text]
}
and its ideone.
The solution is derived from idea expressed by Nickolay Merkin below.
But he suspect UB somewhere in turn_A_to<>().
I have the same problem, and while I'm not using it, one solution I thought of is to have a single class and make the methods switches based on a "item type" number in the class. Changing type is as easy as changing the type number.
class OneClass {
int iType;
const char* Wears() {
switch ( iType ) {
case ClarkKent:
return "glasses";
case Superman:
return "cape";
}
}
}
:
:
OneClass person;
person.iType = ClarkKent;
printf( "now wearing %s\n", person.Wears() );
person.iType = Superman;
printf( "now wearing %s\n", person.Wears() );