How would I provide a template specialisation for the Derived class in this simple case, assuming the Base cannot be changed - in my real code, Base is a library that I cannot change.
#include <iostream>
#include <memory>
class Base
{
public:
virtual void foo() { std::cout << "In base\n"; }
};
class Derived: public Base
{
public:
virtual void foo() { std::cout << "In derived\n"; }
};
template<typename T>
void wibble(T &&baz)
{
std::cout << "In wibble for default\n";
baz->foo();
}
// How do I provide a specialisation here?
//template<typename what_goes_here>
//void wibble(what_goes_here &&baz)
//{
// std::cout << "In wibble for derived\n";
// baz->foo();
//}
int main()
{
std::shared_ptr<Base> bar = std::make_shared<Derived>();
bar->foo();
wibble(bar);
return 0;
}
I want to be able to use a separate template when the actual type contained within the shared pointer is Derived.
The proper tool here is to use dynamic_cast<Derived*>. This is runtime information and as such must be queried at runtime.
Something like
void wibble(std::shared_ptr<Base*> baz){
if(auto derived =dynamic_cast<Derived*>(baz.get())){
// user derived pointer.
}
}
should allow you achieve something similar to what you want.
If your keyboard is missing *, you can also (thanks Eljay)
if(auto derived = std::dynamic_pointer_cast<Derived>(baz)){
// use derived
}
This is just one more case where templates and polymorphism doesn't really play nice with each other, mainly because of the compile time/runtime dichotomy.
Related
I have a component in a software that can be described by an interface / virtual class.
Which non-virtual subclass is needed is decided by a GUI selection at runtime.
Those subclasses have unique methods, for which is makes no sense to give them a shared interface (e.g. collection of different data types and hardware access).
A minimal code example looks like this:
#include <iostream>
#include <memory>
using namespace std;
// interface base class
class Base
{
public:
virtual void shared()=0;
};
// some subclasses with shared and unique methods
class A : public Base
{
public:
void shared()
{
cout << "do A stuff\n";
}
void methodUniqueToA()
{
cout << "stuff unique to A\n";
}
};
class B : public Base
{
public:
void shared()
{
cout << "do B stuff\n";
}
void methodUniqueToB()
{
cout << "stuff unique to B\n";
}
};
// main
int main()
{
// it is not known at compile time, which subtype will be needed. Therefore: pointer has base class type:
shared_ptr<Base> basePtr;
// choose which object subtype is needed by GUI - in this case e.g. now A is required. Could also have been B!
basePtr = make_shared<A>();
// do some stuff which needs interface functionality... so far so good
basePtr->shared();
// now I want to do methodUniqueToA() only if basePtr contains type A object
// this won't compile obviously:
basePtr->methodUniqueToA(); // COMPILE ERROR
// I could check the type using dynamic_pointer_cast, however this ist not very elegant!
if(dynamic_pointer_cast<A>(basePtr))
{
dynamic_pointer_cast<A>(basePtr)->methodUniqueToA();
}
else
if(dynamic_pointer_cast<B>(basePtr))
{
dynamic_pointer_cast<B>(basePtr)->methodUniqueToB();
}
else
{
// throw some exception
}
return 0;
}
Methods methodUniqueTo*() could have different argument lists and return data which is omitted here for clarity.
I suspect that this problem isn't a rare case. E.g. for accessing different hardware by the different subclasses while also needing the polymorphic functionality of their container.
How does one generally do this?
For the sake of completeness: the output (with compiler error fixed):
do A stuff
stuff unique to A
You can have an enum which will represent the derived class. For example this:
#include <iostream>
#include <memory>
using namespace std;
enum class DerivedType
{
NONE = 0,
AType,
BType
};
class Base
{
public:
Base()
{
mType = DerivedType::NONE;
}
virtual ~Base() = default; //You should have a virtual destructor :)
virtual void shared() = 0;
DerivedType GetType() const { return mType; };
protected:
DerivedType mType;
};
// some subclasses with shared and unique methods
class A : public Base
{
public:
A()
{
mType = DerivedType::AType;
}
void shared()
{
cout << "do A stuff\n";
}
void methodUniqueToA()
{
cout << "stuff unique to A\n";
}
};
class B : public Base
{
public:
B()
{
mType = DerivedType::BType;
}
void shared()
{
cout << "do B stuff\n";
}
void methodUniqueToB()
{
cout << "stuff unique to B\n";
}
};
// main
int main()
{
shared_ptr<Base> basePtr;
basePtr = make_shared<B>();
basePtr->shared();
// Here :)
if(basePtr->GetType() == DerivedType::AType)
static_cast<A*>(basePtr.get())->methodUniqueToA();
else if(basePtr->GetType() == DerivedType::BType)
static_cast<B*>(basePtr.get())->methodUniqueToB();
return 0;
}
You can store an enum and initialize it at the constructor. Then have a Getter for that, which will give you the Type. Then a simple static cast after getting the type would do your job!
The goal of using polymorphism for the client is to control different objects with a single way. In other words, the client do not have to pay any attention to the difference of each object. That way, checking the type of each object violates the basic goal.
To achieve the goal, you will have to :
write the concrete method(methodUniqueToX()).
write a wrapper of the concrete method.
name the wrapper method abstract.
make the method public and interface/abstract.
class Base
{
public:
virtual void shared()=0;
virtual void onEvent1()=0;
virtual void onEvent2()=0;
};
// some subclasses with shared and unique methods
class A : public Base
{
private:
void methodUniqueToA()
{
cout << "stuff unique to A\n";
}
public:
void shared()
{
cout << "do A stuff\n";
}
void onEvent1()
{
this.methodUniqueToA()
}
void onEvent2()
{
}
};
class B : public Base
{
private:
void methodUniqueToB()
{
cout << "stuff unique to B\n";
}
public:
void shared()
{
cout << "do B stuff\n";
}
void onEvent1()
{
}
void onEvent2()
{
methodUniqueToB()
}
};
Suppose I have a base class as below:
template <typename T>
class Base {
// implementation
void do_something() { /* ... */ } ;
};
then, I create a Derived class as below, and override the do_something() method:
template <typename T>
class Derived : public Base<T> {
// implementation
void do_something() { /* ... */ } ;
};
I know virtualization does not work in class templates, and I am just hiding the implementation of the methods. but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
my question is, given that static_cast of Derived class to base class gives me the do_something of based class, Is there any way that I can store them as base classes while each has their implementation of do_something() class ?
but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
This is already just not possible in C++. In C++, a vector can only contain objects of the same static type. The only way a vector can contain different types of objects is if their static type is still the same, but they have different dynamic types, but this is type erasure/polymorphism which you said you don't want to use.
I think maybe you need to rethink your requirements, because your question in essence reads: I want to do something, but I don't want to use technique X which is explicitly defined as the only way to do that something in C++!
I did this and it seems to work fine:
#include <iostream>
template <typename T>
struct Base {
virtual void do_something() { std::cout << "Base::do_something()\n"; }
};
template <typename T>
struct Derived : public Base<T> {
virtual void do_something() { std::cout << "Derived::do_something()\n"; }
};
int main() {
Base<int> b;
Derived<int> d;
Base<int> *p;
p = &b;
p->do_something();
p = &d;
p->do_something();
return 0;
}
Output:
Base::do_something()
Derived::do_something()
A little variation of the melpomene's answer (adding a no-template base struct, BaseOfBase, for the Base<T> structs) permit the use of a common vector of base of derived classe of different T types.
A working example
#include <vector>
#include <iostream>
struct BaseOfBase
{ virtual void do_something () = 0; };
template <typename T>
struct Base : public BaseOfBase
{
T val;
void do_something ()
{ std::cout << "Base::do_something() [" << val << "]\n"; };
};
template <typename T>
struct Derived : public Base<T>
{ void do_something()
{ std::cout << "Derived::do_something() [" << this->val << "]\n"; } };
int main ()
{
std::vector<BaseOfBase*> vpbb;
Base<int> bi;
Derived<int> di;
Base<std::string> bs;
Derived<std::string> ds;
bi.val = 1;
di.val = 2;
bs.val = "foo";
ds.val = "bar";
vpbb.push_back(&bi);
vpbb.push_back(&di);
vpbb.push_back(&bs);
vpbb.push_back(&ds);
for ( auto const & pbb : vpbb )
pbb->do_something();
}
When we say virtualization doesn't work in template classes, we don't mean that you can't do virtual functions in a template class, nor does it mean that you cannot override a member function with a specialized version of it.
#melpomene showed an example of overriding in general, and I will show here with specialization:
#include <iostream>
template <typename T>
class Base {
public:
virtual T do_something(T in) { std::cout << "Base::do_something()\n"; return in; }
};
class Derived : public Base<int> {
public:
virtual int do_something(int in) { std::cout << "Derived::do_something()\n"; return in - 1; }
};
void main()
{
Base<int> b;
Derived d;
Base<int> *p = &b;
auto r1 = p->do_something(10);
std::cout << r1 <<std::endl;
p = &d;
auto r2 = p->do_something(10);
std::cout << r2 << std::endl;
}
Which will output
Base::do_something()
10
Derived::do_something()
9
Showing that it perfectly works as expected.
What we do mean when saying that
virtualization does not work in class templates
Basically means that you can't use as a template the derived class when the base is expected.
Consider the above classes Base<T> and Derived, then if we have the following code:
#include <memory>
template <typename T>
void Test(std::unique_ptr<Base<T>> in){ std::cout << "This will not work with derived"; }
void main()
{
Base<int> b;
Derived d;
auto ptr = std::unique_ptr<Derived>(&d);
Test(ptr); // <-- Will fail to compile as an invalid argument
}
it will fail because std::unique_ptr<Derived> does not inherit from std::unique_ptr<Base<T>> although Derived itself inherits from Base<T>.
One of the main benefits of virtual in C++ is being able to use the base class (pointer or reference) to call derived methods.
I'm reading up on using CRTP to implement static polymorphism, but I can't understand how to achieve what I've mentioned above using this technique, because I can't declare a function as taking type Base when this requires a template.
It seems to me that what is described in the article could be achieved by simply using function overloading, so I'm sure that there must be more to this technique.
(PS: this exact problem is alluded to in a comment to an answer to this question, but unfortunately no one had replied to it: "What vtables truly provide is using the base class (pointer or reference) to call derived methods. You should show how it is done with CRTP here.")
Here is my minimal code, which gives the error "missing template arguments before ‘&’ token
void Print(Base& Object)".
#include <cstring>
#include <iostream>
template <typename Derived>
struct Base
{
std::string ToStringInterface() { return static_cast<Derived*>(this)->ToString(); }
std::string ToString() { return "This is Base."; }
};
struct Derived : Base<Derived>
{
std::string ToString() { return "This is Derived."; }
};
void Print(Base& Object)
{
std::cout << Object->ToStringInterface() << std::endl;
}
int main()
{
Derived MyDerived;
// This works, but could have been achieved with a function overload.
std::cout << MyDerived.ToStringInterface() << std::endl;
// This does not work.
Print(MyDerived);
}
Thanks to the comments and answers received, I'm posting my implementation, in case it may come in useful to anyone else.
#include <cstring>
#include <iostream>
template <typename Derived>
class Base
{
public:
std::string ToStringInterface()
{
return static_cast<Derived*>(this)->ToString();
}
};
template<>
class Base<void> : public Base<Base<void> >
{
public:
std::string ToString()
{
return "This is Base (default implementation).";
}
};
class Derived : public Base<Derived>
{
public:
std::string ToString()
{
return "This is Derived.";
}
};
template <typename T>
void Print(Base<T>& Object)
{
std::cout << Object.ToStringInterface() << std::endl;
}
int main()
{
int Decision;
std::cout << "Do you want to create an object of type Base (input 0) or Derived (input 1)? ";
std::cin >> Decision;
if (Decision == 0)
{
Base<void> MyBase;
Print(MyBase);
}
else
{
Derived MyDerived;
Print(MyDerived);
}
}
Well, you need to declare print a template function :
template<class T>
void Print(Base<T>& Object)
{
std::cout << Object.ToStringInterface() << std::endl;
}
Sorry, but it CRTP indeed doesn't work that way. The idea is typically to inject some code into the dependency hierarchy, in a way that is very specific to C++. In your example, you could have e.g. an interface that requires the ToStringInterface() function and use CRTP to bind it to an existing class hierarchy's ToString():
class IStringable
{
virtual string ToStringInterface() = 0;
};
class Unchangeable
{
virtual string ToString();
};
template<class Derived>
class UnchangeableToIStringableMixin
{
virtual string ToStringInterface()
{
return static_cast<Derived*>(this)->ToString();
}
};
class StringableUnchangeable:
public Unchangeable, UnchangeableToIStringableMixin<StringableUnchangeable>
{
};
However, if Unchangeable can actually be changed, you wouldn't do something like that. Don't forget to consider the possibility that CRTP just isn't the right tool for what you are doing.
I am trying to write a c++ abstract class and I can't figure out how to require implementers of this class to contain a static function.
For example:
class AbstractCoolThingDoer
{
void dosomethingcool() = 0; // now if you implement this class
// you better do this
}
class CoolThingDoerUsingAlgorithmA: public AbstractCoolthingDoer
{
void dosomethingcool()
{
//do something cool using Algorithm A
}
}
class CoolThingDoerUsingAlgorithmB: public AbstractCoolthingDoer
{
void dosomethingcool()
{
//do the same thing using Algorithm B
}
}
Now I'd like to do the coolthing without the details of how coolthing gets done. So I'd like to do something like
AbstractCoolThingDoer:dosomethingcool();
without needing to know how the coolthing gets done, but this seems to require a function that is both virtual and static which is of course a contradiction.
The rationale is that CoolThingDoerUsingAlgorithmB may be written later and hopefully the softare that needs cool things done won't have to be rewritten.
EDIT:Not sure I was clear on what I'm trying to accomplish. I have 3 criteria that I'm looking to satisfy
A library that uses abstractcoolthingdoer and does not need to be rewritten ever, even when another coolthingdoer is written that the library has never heard of.
If you try to write a coolthingdoer that doesn't conform to the required structure, then the executable that uses the library won't compile.
coolthingdoer has some static functions that are required.
I'm probably chasing down a poor design, so please point me to a better one. Am I needing a factory?
Maybe, something like this will help (see ideone.com example):
#include <iostream>
class A
{
protected:
virtual void do_thing_impl() = 0;
public:
virtual ~A(){}
static void do_thing(A * _ptr){ _ptr->do_thing_impl(); }
};
class B : public A
{
protected:
void do_thing_impl(){ std::cout << "B impl" << std::endl; }
};
class C : public A
{
protected:
void do_thing_impl(){ std::cout << "C impl" << std::endl; }
};
int main()
{
B b_;
C c_;
A::do_thing(&b_);
A::do_thing(&c_);
return (0);
}
EDIT: It seems to me the OP does not need run-time polymorphism, but rather compile-time polymorphism without need of class instance (use of static functions when the implementation is hidden in the derived classes, no instance required). Hope the code below helps to solve it (example on ideone.com):
#include <iostream>
template <typename Derived>
struct A
{
static void do_thing() { Derived::do_thing(); }
};
struct B : public A<B>
{
friend A<B>;
protected:
static void do_thing() { std::cout << "B impl" << std::endl; }
};
struct C : public A<C>
{
friend A<C>;
protected:
static void do_thing() { std::cout << "C impl" << std::endl; }
};
int main()
{
A<B>::do_thing();
A<C>::do_thing();
return (0);
}
EDIT #2: To force fail at compile-time in case user does not adhere to desired pattern, here is the slight modification at ideone.com:
#include <iostream>
template <typename Derived>
struct A
{
static void do_thing() { Derived::do_thing_impl(); }
};
struct B : public A<B>
{
friend A<B>;
protected:
static void do_thing_impl() { std::cout << "B impl" << std::endl; }
};
struct C : public A<C>
{
friend A<C>;
protected:
static void do_thing_impl() { std::cout << "C impl" << std::endl; }
};
struct D : public A<D>
{
friend A<D>;
};
int main()
{
A<B>::do_thing();
A<C>::do_thing();
A<D>::do_thing(); // This will not compile.
return (0);
}
This looks to me like right place to implement bridge pattern. Maybe this is what you are (unconsciously) willing to achieve. In short you specify an interface and its implementations, then call to your do_thing method in turn calls an implementation on a pointer to implementer class.
C++ example
I would like to store pointers to a Base class in a vector, but then use them as function arguments where they act as a specific class, see here:
#include <iostream>
#include <vector>
class Base {};
template<class T>
class Derived : public Base {};
void Foo(Derived<int>* d) {
std::cerr << "Processing int" << std::endl;
}
void Foo(Derived<double>* d) {
std::cerr << "Processing double" << std::endl;
}
int main() {
std::vector<Base*> vec;
vec.push_back(new Derived<int>());
vec.push_back(new Derived<double>());
Foo(vec[0]);
Foo(vec[1]);
delete vec[0];
delete vec[1];
return 0;
}
This doesn't compile:
error: call of overloaded 'Foo(Base*&)' is ambiguous
Is it possible to make it work? I need to process the elements of the vector differently, according to their int, double, etc. types.
You'll need to use method polymorphism, as it's dynamic, rather than function overloading, which is static (compile-time). To overload on a templated type, you'll need to use template specialization.
Example:
#include <iostream>
#include <vector>
class Base {
public:
virtual void Foo() {
std::cerr << "Processing base" << std::endl;
}
};
template<class T>
class Derived : public Base {};
template <>
class Derived <int> : public Base {
public:
void Foo() {
std::cerr << "Processing int" << std::endl;
}
};
template <>
class Derived <double> : public Base {
public:
void Foo() {
std::cerr << "Processing double" << std::endl;
}
};
int main() {
std::vector<Base*> vec;
vec.push_back(new Derived<int>());
vec.push_back(new Derived<double>());
vec[0]->Foo();
vec[1]->Foo();
delete vec[0];
delete vec[1];
return 0;
}
When you typecast from Derived<int>* to Base*, you lose the information about what derived class you have, unless you use RTTI (RunTime Type Identification).
If you have enabled RTTI, then you can try to typecast a Base* forward to a derived type pointer by using dynamic_cast<>():
void Foo(Base* base)
{
Derived<int>* derivedInt = dynamic_cast<Derived<int>*>(base);
if(derivedInt)
{
Foo(derivedInt);
return;
}
Derived<double>* derivedDouble = dynamic_cast<Derived<double>*>(base);
if(derivedDouble)
{
Foo(derivedDouble);
return;
}
// Handle other cases here.
}
dynamic_cast returns NULL if the pointer doesn't point to the correct type.
Alternatively, if you don't want to use RTTI and dynamic_cast, you have to maintain some means for determining which subclass is stored in your vector (usually an enum value stored along with the pointer, maybe in a pair, or with a method in Base that returns a similar enum) and use reinterpret_cast<>() to typecast the pointer.
Of course it is ambiguous, how can the compiler figure out which specific subclass of Base is held in vec[0].
You can resolve the ambiguity by an explicit cast:
Foo( (Derived<int>*) vec[0] )
or, better, consider using dynamic method resolution:
class Base {
virtual void Foo() = 0;
};
template <class T>
class Derived: Base {
void Foo() { /* .. doFoo<T>(...) .. */ }
};
template<class T> void doFoo() { /* .. general case .. */ }
template<> void doFoo<int>() { /* .. int case .. */}
template<> void doFoo<double>() { /* .. double case .. */}
and in your code just call
vec[0]->Foo()
You can do it like this:
#include <iostream>
#include <vector>
class Base {
public:
virtual void DoFoo() = 0;
};
template<class T>
class Derived : public Base {
public:
virtual void DoFoo() {
Foo(this);
}
};
void Foo(Derived<int>* d) {
std::cerr << "Processing int" << std::endl;
}
void Foo(Derived<double>* d) {
std::cerr << "Processing double" << std::endl;
}
int main()
{
std::vector<Base*> vec;
vec.push_back(new Derived<int>());
vec.push_back(new Derived<double>());
vec[0]->DoFoo();
vec[1]->DoFoo();
delete vec[0];
delete vec[1];
return 0;
}