Suppose you're writing the base for multiple classes. When should you make the base class have all of the dependent operations be virtual and when should the class take a template argument which is a class with the traits necessary?
e.g.
class base
{
public:
virtual void do_run() = 0;
void general_do_run()
{
// general stuff
// then
do_run();
}
};
class child: public base
{
public:
void do_run() override {}
};
vs
template<class traits>
class base
{
public:
void general_do_run()
{
traits::do_run();
}
};
struct child_traits
{
void do_run() { }
};
class child: public base<child_traits>
{
};
I've noticed that the STL seldom uses virtuals (I assume because of the overhead).
In the virtual case I can write:
std::vector<std::unique_ptr<base>>
And I can use this to store multiple different derived classes.
In the template case there is no such straightforward way to store heterogeneous derived classes in a container and do anything useful with them. You'd have to use something like this:
std::vector<std::variant<child, child2, child3>>
Which is possible, but probably consumes more space, is less familiar to most C++ users, and is not at all flexible if someone else wants to add their own derived type without modifying the vector type.
Use virtual for runtime polymorphism. Use templates or other techniques for static (compile-time) polymorphism.
In addition to the answer from John:
Storing different types to a single vector and the potential higher memory consumption by using std::variant can be overcome by using a variant of pointer types like
std::vector< std::unique_ptr<A>, std::unique_ptr<B> >
I see a very big advantage on independent types and std::variant in the fact that we don't need a common base class. Even on heterogeneous classes we can store and do something with the elements. Even if they don't have any common base class or even they do not have a common interface at all!
struct A
{
void Do() { std::cout << "A::Do" << std::endl; }
};
struct B
{
void Do() { std::cout << "B::Do" << std::endl; }
void Foo() { std::cout << "B::Foo" << std::endl; }
};
struct C
{
void Foo() { std::cout << "C::Foo" << std::endl; }
};
int main()
{
using VAR_T = std::variant< std::unique_ptr<A>, std::unique_ptr<B> >;
std::vector<VAR_T> v;
v.emplace_back( std::make_unique<A>() );
v.emplace_back( std::make_unique<B>() );
for ( auto& el: v ) { std::visit( []( auto& el ){ el->Do(); }, el ); }
// You can combine also a vector to other unrelated types which is impossible
// in case of using virtual functions which needs a common base class.
using VAR2_T = std::variant< std::unique_ptr<B>, std::unique_ptr<C> >;
std::vector<VAR2_T> v2;
v2.emplace_back( std::make_unique<B>() );
v2.emplace_back( std::make_unique<C>() );
for ( auto& el: v2 ) { std::visit( []( auto& el ){ el->Foo(); }, el ); }
// and even if some class did not provide the functionality, we can deal with it:
// -> here we try to call Do which is only in type B!
for ( auto& el: v2 ) { std::visit(
[]( auto& el )
{
if constexpr ( requires { el->Do();} )
{
el->Do();
}
else
{
std::cout << "Element did not provide function!" << std::endl;
}
}
, el ); }
}
The argument that "feature xy is less familiar to most C++ users" is a common problem with all kind of domains. If you never had seen a hammer, it might be valid to use a stone to drive the nail. Best fit designs can only be done, if we know the toolset and how to use it. And education of teams is the best investment a tec company can do.
Back to the question what to prefer:
As always it depends on the algorithm you have to implement. If run time polymorphism is fine and fits, use it. If you can't, only as example cause of non common base class, you can drive with std::variant and std::visit.
And for all approaches CRTP comes into play to generate mixins in all its variants.
In programming in general, there is no general "x is always better as y" rule. Designs must fit! In maintainability, resource usage ( memory, time ) usability ...
Related
let's assume I have a super polymorphic base class Shape where many other shape classes are derived from it.
now if I have a vector of Shape pointers that contains a pointer to a list of different shape types like this:
vector<Shape*> p; // p contains pointer to many different shape objects
I know to have access to methods and members of each shape in vector p, I need to use dynamic_cast.
but what if I don't know what vector p actually contains at runtime? how can i safely find the type of an object contained in vector p at runtime?
i also know i can check if casting by dynamic_cast returns NULL or not for success. but does that mean to find the actual type of my shape object in vector p I have to do something like this:
if (dynamic_cast<Circle*> p[i] !=NULL){
// do stuff
}
else if (...) {
}
and repeat this pattern for all other shape types?
but this becomes cumbersome if I have 100 possible shapes. is there any better way to achieve this at rumtime?
ps- consider following scenario:
lets say I need to iterate through the Shape* vector and for example put all the circle objects in a separate vector and vector etc ... now i need to know the actual type of the objects. checking the return if typeid and dynamic_casts for many shapes is not practical.
You can use typeid in typeinfo header.
See for instance this question: How to determine actual object type at runtime in C++;
However, the actual question is "why do you need to know the actual type of your object?": that this is AFAIK not that frequent to need such a functionnality, since polymorphimsm already allows for managing a vast majority of use cases.
I know to have access to methods and members of each shape in vector
p, I need to use dynamic_cast.
No, not necessarily!
In your case, maybe the following is enough, assuming Shape has an area method, (re)defined in Circle and Rectangle (who both extend the Shape class):
std::vector<Shape*> shapes;
Rectangle rect(...);
Circle circle(...);
shapes.push_back( &rect );
shapes.push_back( &circle );
shapes[0]->area(); // --> calls Rectangle::area()
shapes[1]->area(); // --> calls Circle::area()
I came up with solution that I'm not really proud of, but maybe it will be helpfull in creating better one.
Key thing I was trying to achieve was to get rid of explicit dynamic_cast and got this one working. There is still a need to name your derieved type twice though.
Also, it uses std::function which is told to be slow. C++14 required.
I believe there is a way to do it with just smart usage of templates. Or at least get rid of type_switch<A>::cast<B> lanes. Anyway, the code:
#include <iostream>
#include <functional>
#include <typeindex>
#include <unordered_map>
// Basic inheritance cases
struct A
{
virtual void foo() = 0;
};
struct B : public A
{
void foo() override { }
void bfoo() {
std::cout << "B specific\n";
}
};
struct C : public A
{
void foo() override { }
};
template <typename T>
struct type_switch
{
using Func = std::function<void(T&)>;
using Pair = std::pair<std::type_index, Func>;
using Map = std::unordered_map<std::type_index, Func>;
Map map;
type_switch(std::initializer_list<Pair> l) : map(l.begin(),l.end())
{
}
void call(T& a)
{
map[typeid(a)](a);
}
// allows for "oneliner", without explicit 'call', but it could end in creation of
// new type_switch on every loop iteration etc.
type_switch(T&a, std::initializer_list<Pair> l) : type_switch(l){
call(a);
}
template <typename T2>
static Func cast(std::function<void(T2&)> f)
{
static_assert(std::is_base_of<T, T2>::value, "Invalid cast operation on functors, T2 is not base of T");
// lot of functor copyings...
return[f = std::move(f)](T& t) {
f(static_cast<T2&>(t));
};
}
};
int main()
{
B b;
C c;
int local = 0;
type_switch<A> sw = {
{ typeid(B), type_switch<A>::cast<B>( [&local](auto& a) { // auto will deduce into B! No explicit casting
std::cout << "Handle b, local value is " << local << '\n';
a.bfoo(); // B specific
local++; // some outer scode operation
}) } ,
{ typeid(C), type_switch<A>::cast<C>([&local](auto& a) { // auto will deduce into C! No explicit casting
std::cout << "Handle c, local value is " << local << '\n';
local++; // some outer scode operation
})
},
/* // this one would trigger static_assert
{ typeid(int), type_switch<A>::cast<int>([&local](auto& a) { // auto will deduce into C! No explicit casting
std::cout << "Handle int, local value is " << local << '\n';
local++; // some outer scode operation
})
},*/
};
sw.call(b);
sw.call(c);
return 0;
}
There are several ways to detect this at run-time but I cannot find a way to determine if a pointer to a class will be offsetted at compile-time.
class MyA
{
public:
int m_memberI;
};
class MyB
{
public:
double m_memberD;
};
class MyC : public MyA, public MyB
{
};
void main()
{
MyC myC;
void* pVoidB = dynamic_cast< MyB* >( &myC );
if( pVoidB != &myC )
{
std::cout << "Offset needed!" << std::endl;
}
}
// **********************************************************************************
// Ideally, I would prefer something like this
//
// static_assert( std::cast_needs_offset< MyB*, MyC* >::value, "Offset detected!!!" );
// **********************************************************************************
The compilers obviously has that information, but I can't find a type_trait that could help me.
Any trick up your sleeves?
I have found several questions about the same problem. It's not what I want and I cannot use those solutions but after a lot of research, I think it's impossible to accomplish what I am trying to do because first members of each class are unknown at a template library level.
See:
How to do a static assert that a pointer cast is trivial?
and
C++, statically detect base classes with differing addresses?
static_assert(offsetof(MyC, m_memberI) == offsetof(MyA, m_memberI));
static_assert(offsetof(MyC, m_memberD) != offsetof(MyB, m_memberD));
Unfortunately this is useless for my particular problem.
I'm trying to implement a copy+swap idiom to achieve strong-exception safety through a level of abstraction and, although the principle is clear, as it's often the case the devil is in the detail.
Say I have a class that looks like this:
class AConcreteType :
public ISomething,
public ISwappable
{
public:
// From ISwappable
void Swap( ISwappable& );
};
I can now do this within a method that only deals with ISomething:
void AClass::DoSomething( ISomething& something )
{
// say there is a function that allows me to clone 'something'
// Probably it ought to go into an auto_ptr, but for clarity:
ISomething& somethingElse( clone( something ) );
// ... so that at the end, after doing stuff with somethingElese I can do
ISwappable& swappable1 = dynamic_cast<ISwappable&>( something );
ISwappable& swappable2 = dynamic_cast<ISwappable&>( somethingElse );
// ... I may want to check that the concrete types behind the interface are
// actually the same too with something like typeid, but I'll leave that out for clarity
swappable1.Swap( swappable2 );
}
where
void AConcreteType::Swap( ISwappable& swappable )
{
AConcreteType& somethingConcrete = dynamic_cast<AConcreteType&>(swappable);
std::swap( *this, somethingConcrete );
}
This all works, as all the dynamic_casts are on references, which is an operation that throws when the type is not supported; this leaves my objects in a good state as the swap doesn't happen until the very end. But what I'm not comfortable with is the fact that the call swappable1.Swap(swappable2) can still throw (via the same dynamic_cast mechanism), and that would be counter-intuitive for the user of Swap as he would probably not expect anything to throw at that point.
An alternative I thought of was to template ISwappable so as to do away with the dynamic_cast inside the implementation of Swap:
template< typename T >
class ISwappable
{
public:
virtual void Swap( T& ) = 0;
};
so that its implementation is simply
class AConcreteType :
public ISomething,
public ISwappable<AConcreteType>
{
void Swap( AConcreteType& act ) { std::swap( *this, act ); }
};
This allows the Swap call to be non-throw (and allows me to guarantee that the two objects are actually swappable at compile-time), but the problem now is that I have to deal with a concrete type inside DoSomething, but I don't have access to AConcreteType inside that function.
Any ideas?
C++ isn't particularly geared toward inheritance based interfaces. For example, you're implementing a function that takes an ISomething, but it also expects the object to be an ISwappable. Languages geared toward using interfaces like this usually have a direct way to express requirements for multiple interfaces on a single type.
Instead it's probably better in C++ to use templates and then express requirements on those template parameters when necessary. Static assertions and type traits are a pretty simple and readable way of doing this in C++.
template<typename T,typename Interface>
struct implements {
static constexpr bool value = std::is_base_of<Interface,T>::value;
}
template<typename T>
void AClass::DoSomething(T &something ) {
static_assert(implements<T,ISomething>::value, "requires ISomething");
static_assert(implements<T,ISwappable<T>>::value, "requires ISwappable");
T somethingElse = clone(something);
something.Swap(somethingElse);
}
You might also want to move away from using inheritance for interfaces altogether. You can usually get the static type checking on your classes via static_asserts and type traits without inheritance:
template<typename T>
struct is_swappable { static constexpr bool value = ... };
class AConcreteType {
...
};
static_assert(is_swappable<AConcreteType>,"...");
template<typename T>
void AClass::DoSomething(T &something ) {
static_assert(is_something<T>::value, "requires something");
static_assert(is_swappable<T>::value, "requires swappable");
If you ask me, the idea of a ISwappable is already "ill-posed" since you cannot swap abstract types into each other without consequences... What you can swap safely are addresses of interfaces (pointers):
std::unique_ptr<ISomething> tI1(new AConcreteType(1)), tI2(new BConcreteType(2));
std::cout << tI1->IdentifyYourSelf() << std::endl; // -> prints "1"
std::cout << tI2->IdentifyYourSelf() << std::endl; // -> prints "2"
tI1.swap(tI2);
// contents are swapped now
std::cout << tI1->IdentifyYourSelf() << std::endl; // -> prints "2"
std::cout << tI2->IdentifyYourSelf() << std::endl; // -> prints "1"
What can I do to make this work:
template<class C, class V, Test V::*>
class Test {
};
it gives me compiler error:
unknown type name 'Test'
It's a self-referencing template for now, which doesn't seem possible. What could possibly be done to make it work?
EDIT:
Here's what I'd need this for. I want to implement a bi-directional (think parent-child) relationship schema with the least minimum coding effort.
template <class O, class T, Reference<T, O, Reference O::*> T::* opposite>
class Reference
{
T **data;
int count;
public:
Reference(): data(new T*[N]), count(0) {}
~Reference() {delete[] data;}
Reference &add(T *t) {
handleOtherSide();
return link(t);
}
// a lot of stuff to implement this
};
That's the collection class. Here's how it would be used:
class Partner
{
public:
Reference<Partner, Address, &Address::partner> addresses;
};
class Address
{
public:
Reference<Address, Partner, &Partner::addresses> partner;
};
My goal is to have everything necessary for Reference to work be supplied as template argument, so that there is no need to provide constructors for classes like Partner and Address (currently I supply the opposite member pointer as a constructor arg but this requires me to have explicit constructors for the participant classes). I would also need to pass in or calculate an "owner" pointer to the Reference class. I left this problem out here because I want to focus on the self-referencing template aspect.
The easiest way to think of this is boost::bimap. But the problem with bimap is that I don't want the enclosing bimap but just the left and right part of it. bimap is also not feasible because it would lead to one single bimap managing all associations of a specific relationship. It would possibly hold a large number of objects slowing down operations on it.
Are you looking for something like this? It's not self-referencing template, but you can specify derived class as a template type for base class and base class can call derived methods etc.:
template< typename PType, typename PDerived >
class TBase
{
//do stuff with TDerived
public:
bool foo( void )
{
return ( static_cast< PDerived* > ( this )->bar() );
}
};
template< typename PType >
class TDerived : public TBase< PType, TDerived< PType > >
{
friend class TBase< PType, TDerived< PType > > ;
//do stuff
protected:
bool bar( void )
{
return ( true );
}
};
EDIT: Once again, I'm not sure what's your final goal. Here is a solution to what I think you want, or, at least, some hint to what you might use to implement your design. The only requirement that I put is that both TAddress and TPartner have function with same name. See if that's what you need. In principle, you can make a helper class and use CRTP to access member function through a pointer, but I don't think you actually need it.
template< typename PType1, typename PType2 >
class TReference
{
public:
int mFlag;
TReference() :
mFlag( 0 )
{
}
TReference( int fFlag ) :
mFlag( fFlag )
{
std::cout << "Creating reference " << PType1::sName << " -> " << PType2::sName << "." << std::endl;
}
TReference< PType2, PType1 > AccessOpposite( void )
{
PType2 lTmp;
lTmp.Opposite();
return TReference< PType2, PType1 > ( -1 );
}
};
class TPartner;
class TAddress
{
public:
static const char* sName;
TReference< TAddress, TPartner > mRef;
void Opposite( void )
{
std::cout << sName << "::Opposite" << std::endl;
}
};
class TPartner
{
public:
static const char* sName;
TReference< TPartner, TAddress > mRef;
TReference< TAddress, TPartner > Opposite( void )
{
std::cout << sName << "::Opposite" << std::endl;
}
};
const char* TAddress::sName = "TAddress";
const char* TPartner::sName = "TPartner";
int main( void )
{
TAddress lAddress;
TPartner lPartner;
std::cout << lAddress.mRef.mFlag << " " << lPartner.mRef.mFlag << std::endl;
lPartner.mRef = lAddress.mRef.AccessOpposite();
std::cout << lAddress.mRef.mFlag << " " << lPartner.mRef.mFlag << std::endl;
return ( 0 );
}
The problem is, what I want to achieve is not possible in C++, at least not with templates and the amount of code and classes I am aiming at (read: single line of code per member). It starts with the compiler needing forward declarations and fully defined types, which is making by-value members and template arguments of such impossible (in case of cyclic dependencies). Then it is not possible to have a member pointer as a template arg when the class of that member is not yet fully defined. The root cause of all this is how the compiler works: it is single pass. And there is nothing I can do about that.
The solution is to use by-reference members or an OO style base class or a boost::any style container to avoid the templates. With the latter 2 it might be possible to have by-value members.
I have a class that uses several policies that are templated. It is called Dish in the following example. I store many of these Dishes in a vector (using a pointer to simple base class), but then I'd like to extract and use them. But I don't know their exact types.
Here is the code; it's a bit long, but really simple:
#include <iostream>
#include <vector>
struct DishBase {
int id;
DishBase(int i) : id(i) {}
};
std::ostream& operator<<(std::ostream& out, const DishBase& d) {
out << d.id;
return out;
}
// Policy-based class:
template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase {
Appetizer appetizer_;
Main main_;
Dessert dessert_;
public:
Dish(int id) : DishBase(id) {}
const Appetizer& get_appetizer() { return appetizer_; }
const Main& get_main() { return main_; }
const Dessert& get_dessert() { return dessert_; }
};
struct Storage {
typedef DishBase* value_type;
typedef std::vector<value_type> Container;
typedef Container::const_iterator const_iterator;
Container container;
Storage() {
container.push_back(new Dish<int,double,float>(0));
container.push_back(new Dish<double,int,double>(1));
container.push_back(new Dish<int,int,int>(2));
}
~Storage() {
// delete objects
}
const_iterator begin() { return container.begin(); }
const_iterator end() { return container.end(); }
};
int main() {
Storage s;
for(Storage::const_iterator it = s.begin(); it != s.end(); ++it){
std::cout << **it << std::endl;
std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??
}
return 0;
}
The tricky part is here, in the main() function:
std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??
How can I access the dessert? I don't even know the Dessert type (it is templated), let alone the complete type of the object that I'm getting from the storage.
This is just a toy example, but I think my code reduces to this. I'd just like to pass those Dish classes around, and different parts of the code will access different parts of it (in the example: its appetizer, main dish, or dessert).
What you have is not exactly policy-based design IMO... if it were, your class should've actually implemented (i.e. extended) the policies.
Now, back to your question/example. In your container, you store a "DishBase*". Right? From that point on, you loose any compile-time information wrt the actual type of the objects in the collection. So, I'm afraid what you try to do is provably impossible.
What you could do, is use an actual policy-based design, eg.
template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase, Appetizer, Main, Dessert {
}
Then, you could simply use dynamic_cast to check at runtime that you can convert your object to any concrete Appetizer/Dessert/Main.
But from your description, I get the impression that you actually need abstract base classes (i.e. abstract base classes may be the design that makes sense for you, and not policies).
You will need to have appropriate member functions for querying (in this case an overload for the concrete Dessert type). The policies should expose a way of discovery. Here's a short example:
#include <iostream>
using namespace std;
struct TA { virtual string foo() { return "TA::foo\n"; } };
struct DTA : TA { virtual string foo() { return "DTA::foo\n"; } };
template <class T>
struct C {
T t;
};
template <class T>
ostream& operator <<(ostream& o, C<T> c) {
o << c.t.foo();
return o;
}
int main(int argc, char* argv[])
{
C<DTA> c;
cout << c;
}
My understanding is that policy-based template classes are not very container friendly. I just opt for plain old polymorphism for this kind of things. I'd be interested in a solution though.
EDIT: It's perhaps not by coincidence that I cannot find any usage of stl containers throughout Alexandrescu's "Modern C++ Desing" book.
EDIT2: More details on the friction between polymorphism and genericity can be found here http://www.artima.com/cppsource/type_erasure.html. You container can perhaps be made of boost::any objects?