Summary: In search of the standard C++ design pattern for loading different files via constructor
I have a Base class with some functionality that will be used by all derived classes (e.g. Derived_A, Derived_B). The principal difference is that Derived_A and Derived_B override the load function, which is used by the constructor to load a data file (load may also be called explicitly outside the constructor).
I ran into an unexpected problem from this: the load function called by the constructor treats the class as the Base type, but when I use a default constructor and call the load function explicitly, then the virtual function table permits the intended load function to be called.
This smells like a classic problem, but I can't figure out a way to do it (and I was most recently programming in Python, which I believe, due to weak typing, would always call the intended function).
In the same vein, I'd really like Base::load to be pure virtual / abstract (only derived classes will be instantiated); however, that won't compile (I believe, because the compiler sees that the pure virtual function will be called).
Can you help?
Output:
Loading w/ constructor:
Base::load file_A
Base::load file_B Loading w/ function post construction:
Derived_A::load file_A
Derived_B::load file_B
Code:
#include <iostream>
#include <string>
class Base
{
public:
Base() {}
Base(std::string x)
{
load(x);
}
virtual void load(std::string x)
{
std::cout << "\tBase::load " << x << std::endl;
}
};
class Derived_A : public Base
{
public:
Derived_A() {}
Derived_A(std::string x): Base(x) {}
void virtual load(std::string x)
{
std::cout << "\tDerived_A::load " << x << std::endl;
}
};
class Derived_B : public Base
{
public:
Derived_B() {}
Derived_B(std::string x): Base(x) {}
void virtual load(std::string x)
{
std::cout << "\tDerived_B::load " << x << std::endl;
}
};
int main()
{
// simpler code, but it doesn't behave as I hoped
std::cout << "Loading w/ constructor:" << std::endl;
Base*der_a = new Derived_A(std::string("file_A"));
Base*der_b = new Derived_B(std::string("file_B"));
// this is what I want to do
std::cout << "Loading w/ function post construction:" << std::endl;
der_a = new Derived_A;
der_a->load( std::string("file_A") );
der_b = new Derived_B;
der_b->load( std::string("file_B") );
return 0;
}
The behavior you see is well defined in C++ -- it's just not useful in this scenario because the class is not fully constructed when you call load(std::string) from Base::Base(std::string).
There are two immediate approaches:
A
You could use a container type which calls load (and perhaps holds on to the string as well). This may be more practical if you need to hold on to instances (e.g. they may have specialized error information).
class Loader
{
public:
Loader(Base* const p, const std::string& location) : d_base(p)
{
this->d_base->load(location);
}
private:
std::unique_ptr<Base>d_base;
private:
Loader(const Loader&) = delete;
Loader& operator=(const Loader&) = delete;
};
In use:
std::cout << "Loading w/ Loader:\n";
Loader l_der_a(new Derived_A, "file_A");
Loader l_der_b(new Derived_B, "file_B");
B
You could also approach it using a helper function:
class Base {
public:
template<typename T>
static void Load(const std::string& x)
{
T().load(x);
}
Base()
{
}
Base(std::string x)
{
/* load(x); << see Load(const std::string&) */
}
virtual ~Base()
{
}
virtual void load(std::string x) = 0;
};
In use:
std::cout << "Loading w/ Base::Load<T>():\n";
Derived_A::Load<Derived_A>("file_A");
Derived_B::Load<Derived_B>("file_B");
And then there are several other approaches and variations - it depends on what fits your design best. With C++, you certainly have options.
You can look up "Named Constructor Idiom".
Related
I have a hierarchy of classes:
class Base
{
public:
Base():a{5}{}
virtual ~Base(){};
int a;
};
class Derived : public Base
{
public:
Derived():b{10}{}
int b;
};
I then have a class template that operates on whatever type it is instanciated with:
template<typename T>
class DoStuff
{
public:
DoStuff():val{}{}
virtual ~DoStuff(){};
virtual void printDoStuff() = 0;
T getVal(){return val;};
private:
T val;
};
class DoStuffWithInt : public DoStuff<int>
{
public:
virtual void printDoStuff() override {cout << "val = " << getVal() << endl;}
};
class DoStuffWithBase : public DoStuff<Base>
{
public:
virtual void printDoStuff() {cout << "a = " << getVal().a << endl;}
};
Now I would like to have a hierarchy of class like this:
class DoStuffWithBase : public DoStuff<Base>
{
public:
virtual void printDoStuff() {printVal(); cout << "a = " << getVal().a << endl;}
};
// Wrong and will not compile, trying to make a point
class DoStuffWithDerived : public DoStuffWithBase<Derived>
{
public:
void printDoStuff() override {DoStuffWithBase::printDoStuff(); cout << "b = " << getVal().b << endl;}
};
Basically I would like to have DoStuffWithBase that operates on a base be extended so that I can reuse its functions, but the extended class DoStuffWithDerived should operate on a Derived type.
I managed to get something working by templating DoStuffWithBase with a pointer to Base and extending it:
template <class T>
static void deleteIfPointer(const T& t)
{
std::cout << "not pointer" << std::endl;
}
template <class T>
static void deleteIfPointer(T* t)
// ^
{
std::cout << "is pointer" << std::endl;
delete t;
}
template<typename T>
class DoStuff
{
public:
DoStuff():val{}{}
DoStuff(const T& value):val{value}{};
virtual ~DoStuff(){deleteIfPointer(val);}
virtual void printDoStuff() = 0;
T getVal(){return val;};
private:
T val;
};
class DoStuffWithBase : public DoStuff<Base*>
{
public:
// New base
DoStuffWithBase(): DoStuff(new Base()){}
DoStuffWithBase(Base* b) : DoStuff(b){}
virtual void printDoStuff() {printVal(); cout << "a = " << getVal()->a << endl;}
};
class DoStuffWithDerived : public DoStuffWithBase
{
public:
// New derived
DoStuffWithDerived(): DoStuffWithBase(new Derived()){}
void printDoStuff() override {DoStuffWithBase::printDoStuff(); cout << "b = " << static_cast<Derived*>(getVal())->b << endl;}
};
It works but there are several things I don't like:
The code is a lot more complicated, when 99% of the time, I won't need to extend a DoStuffWithX class, I will just use DoStuffWithInt, DoStuffWithClass, DoStuffWithAnotherClass etc... Here I had to add several constructors, a special case destructor and so on.
I have to use pointers and manage them (static_cast when needed, deletion...), all in order to avoid slicing and get the right type. Also, DoStuff::val should theorically not be null, but with a pointer there is no way I can prevent that (or atleast I don't know one). Maybe using smart pointers would help a bit here ? I am not super familiar with them.
I have to manage cases where T is a pointer and when it is not. For example, the deleteIfPointer function above, but also switching between . and -> and probably more.
Is there any simpler way to achieve what I am trying to do ? A design pattern or something else ? Am I stuck with my solution and is it somewhat good ?
Edit: I tried to implement it with std::variant as in #Tiger4Hire's answer:
class Derived : public Base
{
public:
Derived():b{10}{}
int b;
};
class Derived2 : public Base
{
public:
Derived2():c{12}{}
int c;
};
using DerivedTypes = std::variant<Derived, Derived2>;
struct VariantVisitor
{
void operator()(Derived& d)
{
d.b = 17;
}
void operator()(Derived2& d)
{
d.c = 17;
}
};
class DoStuffWithVariant : public DoStuff<DerivedTypes>
{
public:
void handleBasePart(Base& base)
{
cout << "a = " << base.a << endl;
base.a = 10;
}
virtual void printDoStuff() override
{
auto unionVal_l = getVal();
if (std::holds_alternative<Derived>(unionVal_l))
{
std::cout << "the variant holds a Derived!\n";
auto& derived_l = std::get<0>(unionVal_l);
cout << "b = " << derived_l.b << endl;
handleBasePart(derived_l);
}
else if (std::holds_alternative<Derived2>(unionVal_l))
{
std::cout << "the variant holds a Derived2!\n";
auto& derived2_l = std::get<1>(unionVal_l);
cout << "c = " << derived2_l.c << endl;
handleBasePart(derived2_l);
}
std::visit(VariantVisitor{}, unionVal_l);
}
};
What I like about it:
I don't have to use pointers.
I feel the code is less tricky, easier to understand.
What I don't like about it:
The code is all in one place and it deals with all the possible Derived types (and even the Base type) at once whereas with inheritance, classes are more specialized, you can really look at a class and directly know what it does, what it overrides etc... On the other hand one could argue that it means the algorithm is in one place instead of dispatched all over the classes hierarchy.
You can't have an abstract base class as your interface.
All in all it is a really good alternative, but I am still wondering if there is a simpler way to implement dynamic polymorphism ? Do you necessarily have to resort to (base class) pointers with dynamic polymorphism ? Are std::variant the way to go now ?
Edit2: 2 other drawbacks with variants that I didn't notice at first:
All your derived class and your base class have to be defined in the same library. Clients can't easily add a new Derived class since it would mean modifying the variant and they might not have access to it.
On the project I am working on, base classes are defined in one library, and are derived in other independant "sub" libraries. So if I try to use variant in my main library, it won't be able to access the Derived types in the sub libraries, which is a major issue.
If your base class implenting the variant (DoStuff here) has other members, when you call std::visit on the variant, you might have to also embark the needed other members of DoStuff. I think you should be able to use lambdas to capture them, but still, it's a lot less straightforward than using them directly as in the case of inheritance.
Your core problem is that you cast away your type information.
C++ will always call the right function, if it knows the correct type. This is why the pattern of pointer-to-base is almost always an anti-pattern (even though it is often taught as the "C++" way to do things).
Modern C++-style is to hold things as strongly-typed pointers, and cast them to the base pointer object, only when calling a function that takes a base-pointer as a parameter.
The standard supports this way of working by providing std::variant. Thus rather than
std::vector<Base*> my_list_of_things;
my_list_of_things.push_back(new Derived); // casting away type is bad
You start with
using DerivedTypes = std::variant<std::unique_ptr<Derived1>,
std::unique_ptr<Derived2>/*,etc*/>;
std::vector<DerivedTypes> my_list_of_things;
Now you can iterate over the list, calling a function which takes a pointer-to-base, casting away the type information only during the call.
You can also visit the members of the list, with a function (often a lambda) that knows exactly the type it is working on.
So you get the best of both worlds!
This does assume you have access to C++17 or above though, also that you are not working with code that is a library (compiled) but allows the library user to make their own classes. For example, libraries like Qt can't use this way of working.
If you don't have access to C++17, you may find curiously recursing templates fit much of what you are doing. (This is a controversial pattern though, as it is ugly and confusing)
The Non-virtual Interface idiome (NVI) is pretty self explanatory: You don't write public virtual functions, but public functions that call a private virtual implementation function, like so:
class Object{
virtual void v_load();
public:
void load(){ v_load(); }
}
This enables you, the base class author, to check and enforce pre- and post-conditions or apply other functions so the author of deriving classes can't forget about them.
Now when you are the deriving author, you may want to write a base class yourself - let's call it Pawn - that extends on the functionality of load() and therefore has to override v_load(). But now you are facing a problem:
When you override v_load(), other clients that want to derive from your class, will always overwrite that behaviour, and they can not call Pawn::v_load() because it is a private function, neither can they call Pawn::load() because it is defined as { v_load; } in Object which will of course lead to an infinite loop. Additionally, requiring them to do so could lead to mistakes when they forget that call. If I would want them to enable that, I would have to specify the acces to v_load() as protected in Object, which seems like an ugly solution as it would weaken the encapsulation of Object greatly.
You could of course still override v_load() to call a new function v_pawnLoad(), which is then overridden by clients, but that seems very error-prone as a lot of clients will probably overload the wrong function.
So, how can I design Pawn in such a way that clients can still override v_load() while keeping the ability to check pre-conditions or call other functions and (if possible) not enabling, let alone requiring clients of Object or Pawn to call the base v_load() implementation?
If your intention is to allow people to "extend" as opposed to "replace" load's behaviour, then put the code you currently have in v_load in load then call an empty v_load in the end.
Or you could just make v_load protected if you want to let people choose between "replacing" or "extending".
If you just want to allow them to replace the behaviour, your code is fine as it is.
As a bonus, in all these 3 variants you can change "allow" with "force" by making your v_load a pure virtual if you have no default behaviour.
If you wish to limit the override to your Pawn child class, add the final keyword to v_load in Pawn and use another virtual function to allow children of Pawn to customise its behaviour.
How about mixin' in some CRTP?
#include <iostream>
class BaseObject
{
private:
virtual void v_load() = 0;
public:
void load() { v_load(); }
};
template<typename Derived>
class Object : public BaseObject
{
private:
virtual void v_load() { static_cast<Derived&>(*this).load(); }
};
class Pawn : public Object<Pawn>
{
public:
void load() { std::cout << "Pawn::load()" << std::endl; }
};
class BlackPawn : public Pawn
{
private:
virtual void v_load() {
std::cout << "BlackPawn::v_load()" << std::endl;
std::cout << "- "; Pawn::load();
}
public:
void load() {
std::cout << "BlackPawn::load()" << std::endl;
std::cout << "- "; Pawn::load();
}
};
class BigBlackPawn : public BlackPawn
{
private:
virtual void v_load() {
std::cout << "BigBlackPawn::v_load()" << std::endl;
std::cout << "- "; BlackPawn::load();
}
public:
void load() {
std::cout << "BigBlackPawn::load()" << std::endl;
std::cout << "- "; BlackPawn::load();
}
};
template<typename T>
void load(T& x)
{
x.load();
}
void vload(BaseObject& x)
{
x.load();
}
int main()
{
Pawn p;
BlackPawn bp;
BigBlackPawn bbp;
load(p);
load(bp);
load(bbp);
std::cout << std::endl;
vload(p);
vload(bp);
vload(bbp);
}
Output on ideone.
I need help getting the broken part of this code working.
How do I tag dispatch two functions (that return different value-types) based on a string?
If the overall code can be simplified with the intent of dispatching with strings, please do make recommendations. TY.
Requirements:
Dispatch based on a string
Rectangle overload needs to return int, while Circle overload needs to return std::string
The mapping from Rectangle_Type to int and Circle_Type to std::string is fixed and known at compile time. Part of my problem is std::map is a run-time construct: I don't know how to make the std::string to tag mapping a compile-time construct.
If necessary, run-time resolution is okay: however, the dispatch must allow for different return types based on the enum/type resolved to.
CODE
#include <map>
#include <string>
#include <iostream>
struct Shape { };
struct Rectangle_Type : public Shape { using value_type=int; };
struct Circle_Type : public Shape { using value_type=std::string; };
Rectangle_Type Rectangle;
Circle_Type Circle;
static std::map<std::string,Shape*> g_mapping =
{
{ "Rectangle", &Rectangle },
{ "Circle", &Circle }
};
int tag_dispatch( Rectangle_Type )
{
return 42;
}
std::string tag_dispatch( Circle_Type )
{
return "foo";
}
int
main()
{
std::cerr << tag_dispatch( Circle ) << std::endl; // OK
std::cerr << tag_dispatch( Rectangle ) << std::endl; // OK
#define BROKEN
#ifdef BROKEN
std::cerr << tag_dispatch( (*g_mapping["Rectangle"]) ) << std::endl;
std::cerr << tag_dispatch( (*g_mapping["Circle"]) ) << std::endl;
#endif
}
Unless C++11 has changed this.. The problem is that you are dereferencing a Shape* pointer, which means the resulting datatype (Shape&) does not have a valid overload of tag_dispatch.
You can do something like g_mapping["Rectangle"]->tag_dispatch(). Or more cleanly rewrite as below.
std::string tag_dispatch( Shape& shape)
{
return shape->tag_dispatch();
}
This way you can support non Shape objects with an identical interface. Both need you to make tag_dispatch as a virtual function of Shape as well.
C++ does not have dynamic dispatch. This is probably what you expect to happen. You can emulate it with dynamic_cast, but that's slow and not recommended. You could use a virtual function returning an enum for the type though.
class base
{
public:
virtual ~base() // Don't forget the virtual destructor if you want to inherit from it!
{}
enum type
{
a,
b,
};
virtual type get_type() const = 0;
};
class a : public base
{
public:
virtual type get_type()
{
return base::type::a;
}
};
class b : public base
{
public:
virtual type get_type()
{
return base::type::b;
}
};
I would like to implement the following thing in C++:
I would like to have a bunch of child classes of a single class with the ability to call a function that takes a pair of objects of any of these types. There is supposed to be a generic implementation that is called for mixed types or the base type and specialised implementations which get called if two objects of the same derived type are used as arguments.
As far as I know, this is a classic application of double dispatch. However, I have the following constraint:
It must be possible to derive new classes from the existing ones and add new pair-functions for these new classes without changing existing classes, for instance in an external library..
The approach I proposed in my last question is faulty, and the solution proposed there only works for types that are known at the time when the base class is written.
Any suggestion on how to implement this? Is that even possible?
Update: Code says more than a thousand words. The following approach works:
#include <iostream>
class B;
class A
{
public:
virtual void PostCompose(A* other)
{
other->PreCompose(this);
}
virtual void PreCompose(A* other)
{
std::cout << "Precomposing with an A object" << std::endl;
}
virtual void PreCompose(B* other);
};
class B : public A
{
public:
using A::PreCompose;
virtual void PostCompose(A* other)
{
other->PreCompose(this);
}
virtual void PostCompose(B* other)
{
other->PreCompose(this);
}
virtual void PreCompose(B* other)
{
std::cout << "Precomposing with a B object" << std::endl;
}
};
void A::PreCompose(B* other)
{
PreCompose((A*)other);
}
int main()
{
B b;
A* p = &b;
p->PostCompose(p); // -> "Precomposing with a B object"
}
but it requires knowledge of B when implementing A. Is there a better way?
Since the derived classes only need to detect if the parameter type matches the object type, you can just use a straightforward check.
virtual void foo( base *argument_base ) {
if ( derived *argument = dynamic_cast< derived * >( argument_base ) ) {
argument->something = pair_match_foo;
} else {
base_class::foo( argument_base );
}
}
I have a questions about C++ templates. More specifally, by using template arguments for inheritance.
I am facing strange behaviour in a closed-source 3rd party library. There is a C method
factoryReg(const char*, ICallback*)
which allows to register a subclass of ICallback and overwrite the (simplified) methods:
class ICallback
{
public:
virtual void ENTRY(void* data) = 0;
virtual void EXIT(void* data) = 0;
const char* getName() { return _name; } const
ICallback(const char* name) : _name(name) {}
virtual ~ICallback() {}
private:
const char* _name;
};
I have
class BaseCallback : public ICallback
{
public:
BaseCallback(const char* name) : ICallback(name) {}
virtual void ENTRY(void* data) {
std::cout << "in ENTRY base" << std::endl;
}
virtual void EXIT(void* data) {
std::cout << "in EXIT base" << std::endl;
};
class SpecialCallback : public BaseCallback
{
public:
SpecialCallback(const char* name) : BaseCallback(name) {}
virtual void ENTRY(void* data) {
// actually, it's 3rd party code too - assumed to do something like
...
BaseCallback::ENTRY();
}
// no redecl. of EXIT(void* data)
};
template <typename Base>
TemplCallback : public Base
{
public:
TemplCallback(Base& myT) : Base(myT.getName()), _myT(myT)
virtual void ENTRY(void* data) {
std::cout << "in ENTRY templ." << std::endl;
_myT.ENTRY();
}
virtual void EXIT(void* data) {
std::cout << "in EXIT templ." << std::endl;
_myT.EXIT();
}
private:
Base& _myT;
}
Upon registering
SpecialCallback spc("validName");
TemplCallback<SpecialCallback> myCallback(spc);
factoryReg(spc.getName(), &myCallback);
...
// output: "in ENTRY base"
// "in EXIT base"
the callback somehow does not work (debug output not being put out // breakpoints do not apply).
If I omit implementation of the EXIT(void* data) method in my template class TemplCallback - everything works fine!
// output: "in ENTRY templ."
// "in EXIT base"
Is this expected behaviour? I have been told it might be an issue of the MSVC compiler 13.10.6030 I use. Not sure about that.
BTW: The template idea presented here might not be the best choice for whatever I am trying to do ;)
But I am still interested in the matter itself, regardless about design questions.
I suspect that factoryReg doesn't actually invoke the callback, but stores the pointer and invokes the callback when something happens.
If that is the case, then this code:
TemplCallback<SpecialCallback> myCallback(spc);
factoryReg(spc.getName(), &myCallback);
causes factoryReg to store pointer to a temporary, which will go out of scope as soon as your registration function returns. Thus, when the callback is invoked, the object is not alive and you have undefined behaviour.
Your TemplCallback class looks funny. I don't think you actually want it to use a different object, but to invoke the inherited versions of ENTRY and EXIT:
template <class Base>
class TemplCallback : public Base
{
public:
TempCallback(const char* name) : Base(name)
{}
virtual ENTRY(void* data)
{
// do special processing
Base::ENTRY(data);
}
virtual EXIT(void* data)
{
// do special processing
Base::EXIT(data);
}
};
OK, it seems that it is safe to assume that SpecialCallback::ENTRY() calls BaseCallback::EXIT() somehow.
Can't be 100% sure, because it's closed source - but it's quite likely.
So much for "callback" functions...