I have an example like the one below in C++ where I receive a pointer to base class, exampleParent, and would like to cast it to a pointer to the inherited class example (in reality I just want to call a function on example) . The caveat is that the inherited class is templated. In the example below, I know the template is of type int so there is no problem. In general, what would be a good way to do this if I am not aware before hand the type of the template?
class exampleParent{};
template<typename P>
class example: public exampleParent
{
public:
int do_something() const
{
std::cout<<"I am doing something"<<std::endl;
return 0;
}
};
boost::shared_ptr<const exampleParent> getPtr()
{
return boost::make_shared<const example<int>>();
}
int main()
{
boost::shared_ptr<const exampleParent> example = getPtr();
auto example_ptr = boost::dynamic_pointer_cast<const example<int>>(example);
return example_ptr-> do_something();
}
One solution I propose is to change the code to something like this:
class exampleParent{};
class something_interface: public exampleParent
{
public:
virtual int do_something() const = 0 ;
};
template<typename P>
class example: public something_interface
{
public:
int do_something() const override
{
std::cout<<"I am doing something"<<std::end;
return 0;
}
};
boost::shared_ptr<const exampleParent> getPtr()
{
return boost::make_shared<const example<int>>();
}
int main()
{
boost::shared_ptr<const exampleParent> example = getPtr();
auto example_ptr = boost::dynamic_cast<const something_interface>(example);
return example_ptr->do_something();
}
This would work, but it feels a bit of a hack: something_interface should not really exist, as it has no object oriented interpretation in itself.
Any help would be appreciated!
If you can make exampleParent an abstract class (if you can modify that class at all), that would be the best:
class exampleParent
{
public:
virtual ~exampleParent() = default;
virtual int do_something() const = 0;
};
template<typename P>
class example: public exampleParent
{
public:
int do_something() const override
{
std::cout<<"I am doing something"<<std::endl;
return 0;
}
};
Then you don't need a cast to invoke that method.
If you cannot touch this exampleParent class, go on with the intermediate one as you proposed, but remember to actually inherit exampleParent and don't throw exception, just make the method pure virtual:
class intermediate: public exampleParent
{
public:
~intermediate() override = default;
virtual int do_something() const = 0;
};
Otherwise the only way is to do dynamic_pointer_cast for all possible types and check the cast result, because different instances of template class are just different types in general. Of course it doesn't make sense if there is infinite number of possible template parameters P.
Related
I have an enum class Type. If I have a base class and a derived class like this:
template<Type T>
class Templated
{
public:
Type GetType() const
{
return T;
}
};
class DerivedTemplated : public Templated<Type::None>
{
};
Is this better in any way than having this:
class NoTemplate
{
public:
virtual Type GetType() const = 0;
};
class DerivedNoTemplate : public NoTemplate
{
public:
Type GetType() const override { return Type::None; }
};
Using templates is not necessary in this case, but I don't know if I should use them or not. I often store polymorphic collections of the base class, so in the templated case I would have to create an interface:
class ITemplated
{
public:
virtual Type GetType() const = 0;
};
and derive Templated from it. Are there any benefits to the templated one over the pure virtual function?
I think the first makes no sense. Because how would you use this? For example
template<Type T>
int int_of_type(const Templated<T> &bar) {
return hash(bar.get_type());
}
why not just write:
template<Type T>
int int_of_type(const Templated<T> &) {
return hash(T);
}
or
template<Type T>
int int_of_type<T>() {
return hash(T);
}
I see no way the get_type can be used where you couldn't just use T directly. Maybe you need a more complex example to show what you are trying to solve.
Is there a way to force implementation of a method in a child class where the implementation will have a different signature for each derived class?
I know I can do this, using pure virtual:
class Base {
public:
virtual void getValue(string& s) = 0;
}
class Derived : public Base {
public:
void getValue(string& s);
}
Above, pure virtual getValue in the base class forces the derived class to implement getValue. But what I really want to do is something like this: Force each derived class to implement getValue() but each with a different signature:
class Base {
public:
void getValue() = 0;
}
class Derived_A : public Base {
public:
void getValue(string& s);
}
class Derived_B : public Base {
public:
void getValue(int *j);
}
The problem with the above is that, due to name mangling, each signature is effectively a different function, and thus Derived_A and Derived_B inherit getValue() = 0 and the compiler thinks that they also are abstract.
I've been playing around with some different ways to do this, but it appears to me there is no way to do it. I'm thinking I should simply not declare getValue in the Base class and then just make sure each derived class implements their version of it.
If use of CRTP would work for you, you can use:
#include <string>
template <typename TypeSelector>
class Base {
public:
using type = typename TypeSelector::type;
virtual void getValue(type t) = 0;
};
struct TypeSelector_A {
using type = std::string&;
};
class Derived_A : public Base<TypeSelector_A> {
public:
void getValue(std::string& s) { /* Add real implementation */ }
};
struct TypeSelector_B {
using type = int*;
};
class Derived_B : public Base<TypeSelector_B> {
public:
void getValue(int* j) { /* Add real implementation */ }
};
int main()
{
Derived_A a;
Derived_B b;
}
But what I really want to do is something like this: Force each derived class to implement getValue() but each with a different signature
The whole point of having virtual function (abstract or not) is that you can use it with pointer or reference to the base class which means you would use signature of the function from the base class. With that having what you want is completely useless. What you want can be implemented by returning std::variant or std::any with every virtual function in tree so keeping signature the same.
You should think how would you use such concept if it would be possible. If you think somethink like this:
void foo( Base *b ) {
if( auto *d = dynamic_cast<Derived_A *>( b ) ) {
std::string str;
d->getValue( str );
...
}
if( auto *d = dynamic_cast<Derived_B *>( b ) ) {
int i = 0;
d->getValue( &i );
...
}
}
then getValue() does not need to be virtual, you only need vritual destrictor in Base. But this is considered bad design.
I have a generic IDetachable interface, which provides one method:
template<class T>
class IDetachable {
public:
virtual T detached() const = 0;
};
I have these example classes:
class A: public IDetachable<A> {
virtual A detached() const override {
// some implementation which returns a detached A object
}
};
The problem occurs when inheriting B:
class B: public A, public IDetachable<B> {
virtual B detached() const override {
// some implementation which returns a detached B object
}
};
clang++ tells me:
error: virtual function 'detached' has a different return type ('B')
than the function it overrides (which has return type 'A')
To me it seems, that the compiler automatically chose the first parent for the override keyword. Is there any chance to tell the compiler which parent's method I intended to inherit with the override keyword?
The problem isn't about how to override one or the other its the fact that you can't have two functions with the same signature and different return types.
Consider:
template<class T, class U>
class IDetachable {
public:
virtual ~IDetachable() {}
virtual T detached() const = 0;
virtual U detached() const = 0; // whoopse problem
};
It doesn't matter how you end up with two same-signature functions returning different types its always illegal.
#AdrianMay provides a working answer. He changes the signatures of the functions.
You could pass a dummy T to detach:
template<class T>
class IDetachable {
public:
virtual T detached(T*dummy) const = 0;
};
You ignore that parameter but now you can specialise on it.
Do you just want return type covariance? It works only on pointers and references:
template<class T>
class IDetachable {
public:
virtual T* detached() const = 0;
};
class A: public IDetachable<A> {
virtual A* detached() const override {
// some implementation which returns a detached A object
}
};
class B: public A, public IDetachable<B> {
virtual B* detached() const override {
// some implementation which returns a detached B object
}
};
int main() {
IDetachable<A> *da = new A;
A *a = da->detached();
IDetachable<B> *db = new B;
B *b = db->detached();
}
Here is what I am trying to achieve:
I have a list of Classes (Class1 to Classn) which inherit from a main Class
I would like to be able to instanciate an object of any of the n classes without having to do a large switch case (or equivalent). something along the lines of:
static ClassPointerType const * const ArrayOfClassTypes[]={ Class1, Class2, .. Classn };
static Class *GetObjectOfClass(int i)
{
return new ArrayOfClassTypes[i](some parameters for the constructor);
}
You can do that in other OO langues like Delphi where you have a TClass type and can get the class of an object... but I was not able to locate the equivalent functionality in C++.
Are you looking for something like this?
template<typename T>
std::unique_ptr<base> make()
{
return std::unique_ptr<base>(new T);
}
class factory
{
static constexpr std::unique_ptr<Base> (*fns[])(){make<derived_a>, make<derived_b>};
std::unique_ptr<base> get_object_of_class(int const i)
{
if (i < 0 || sizeof fns / sizeof *fns <= i) {
return nullptr;
}
return fns[i]();
}
};
You can add virtual method Clone to your base class and have it pure virtual (= NULL). Have there all required parameters.
Then you can override it in every subclass and create concrete classes there.
And in your factory do:
static ClassPointerType *GetObjectOfClass(int i)
{
return new ArrayOfClassTypes[i]->Clone(some params for the constructor);
}
And your array should contain concrete classes which you will clone:
static ClassPointerType* const ArrayOfClassTypes[]={ new ClassPointerType1(),new ClassPointerType2(), .. new ClassPointerTypeN() };
Complete example as requested:
// base class
class ClassPointerType
{
…
public:
virtual ClassPointerType* Clone(your params) = NULL;
};
// concrete classes
class ClassPointerType1 : public ClassPointerType
{
…
public:
// note: it clones own concrete instance
virtual ClassPointerType* Clone(your params) {return new ClassPointerType1(your params)};
}
class ClassPointerType2 : public ClassPointerType
{
…
public:
virtual ClassPointerType* Clone(your params) {return new ClassPointerType2(your params)};
}
…
class ClassPointerTypeN : public ClassPointerType
{
…
public:
virtual ClassPointerType* Clone(your params) {return new ClassPointerTypeN(your params)};
}
I implemented something alike recently. In my approach I stored a list of static create-functions instead and feeded a factory class with that
I implemented a templated base class wich
a) is able to register the derived into a factory class
b) implicitly forces the derived class to provide static functions.
However, you have to announce each derived class once. You can use it like this:
int main(int argc, char* argv[])
{
DerivedA::announce();
//and later
IInterface * prt = SingeltonFactory::create(DerivedA::_type);
delete prt;
return 0;
}
The Derived class DerivedA is defined as:
class DerivedA :
public IInterface,
public StaticBase<DerivedA>
{
public:
using StaticBase::announce;
static IInterface * create(){ return new DerivedA; }
static const std::string _type;
};
const std::string DerivedA::_type=std::string("DerivedA");
And the static Base class forcing the _type attribute and the create function to exist are defined as follows:
template<class TDerived>
class StaticBase
{
protected:
static void announce()
{
// register into factory:
SingeltonFactory::registerFun(TDerived::_type,TDerived::_create());
// The call of _type and _create implicitly forces the derived class to implement these, if it is deriving from this Base class
}
};
The factory class does contain a map of
std::map<std::string,tFunPtr>
where typedef tFunPtr is:
typedef IInterface * (*tFunPtr)(void);
This map you can use as an "array of classes" in order to handle it like an object. Thus, you represent the classes by a function pointer of the static create function
Does this answer your requirements? Shall I provide the factory class?
Assuming you are using a C++11 compiler here is a solution equivalent to the one provided earlier but less tricky and clever:
#include <iostream>
#include <memory>
#include <array>
class Base {
public:
virtual void doSomething() = 0;
};
class Der1: public Base {
private:
void doSomething() override {
std::cout << "Der1 did something" << std::endl;
}
};
class Der2: public Base {
private:
void doSomething() override {
std::cout << "Der2 did something" << std::endl;
}
};
template <typename T>
std::unique_ptr<Base> make() {
return std::unique_ptr<T>(new T);
}
int main() {
std::array<std::function<std::unique_ptr<Base>(void)>, 2> arr{make<Der1>,
make<Der2>};
auto obj = arr[0]();
obj->doSomething();
obj = arr[1]();
obj->doSomething();
}
You can use std::bind too to pass arguments to make if you have to use a non-default contructor
Hope that helps
No, in C++ classes are not first-order entities.
(I just noticed everybody is providing a solution to your problem but not precisely answering your question.)
I want to make a class with a member function that takes a reference to another class, where both classes are derived from abstract classes. I get a compiler error that the class Container is abstract because it doesn't implement addElem().
class Ielem
{
public:
virtual void action() = 0;
};
class Elem: public Ielem
{
public:
void action() {};
void extra() {};
};
class Icontainer
{
public:
virtual void addElem(Ielem &elem) = 0;
};
class Container: public Icontainer
{
public:
void addElem(Elem &elem) { elem.extra(); };
};
int main(int argc, char* argv[])
{
Elem e;
Container c;
c.addElem(e);
return 0;
}
It seems like this ought to work, because any reference to an Elem is also a reference to an Ielem. It compiles if I make Container::addElem take a reference to an Ielem. But then Container::addElem() can't call Elem::extra() unless I use dynamic_cast, which isn't available on the embedded compiler I'm using, or a regular cast, which isn't type safe.
Suggestions?
It's the wrong way round: the base class Icontainer specifies that addElem can take any Ielem object as an argument, but in your derived class you accept only Elem. This is a "narrower" type, so the contract "I'll accept any Ielem you throw at me" specified in the base class is violated.
I think templates would be the solution here. You don't even need the base classes anymore. Something like this:
class Elem
{
public:
void action() {};
void extra() {};
};
template<typename ElemType>
class Container
{
public:
void addElem(ElemType &elem) { elem.extra(); };
};
int main(int argc, char* argv[])
{
Elem e;
Container<Elem> c;
c.addElem(e);
return 0;
}
As a bonus, you can now use Container with any type that has an extra() function, and it will just work.
The problem is simply that your virtual method doesn't have the same signature as the concrete method which is intended to overload it; so the compiler sees it as a different function entirely and complains because you haven't implemented void addElem(Ielem &elem). This is one solution, which you probably don't want--
class Icontainer
{
public:
virtual void addElem(Elem &elem) = 0; //Ielem -> Elem
};
It depends on all your other constraints but I think what I would do--and what seems to conform to general design guidelines, e.g. Sutter & Alexandreascu, would be to create an intermediate abstract class with the full interface--
class Melem: public Ielem
{
public:
// void action() {}; //Already have this form Ielem
void extra() = 0;
};
and then
class Icontainer
{
public:
virtual void addElem(Melem &elem) = 0;
};
class Container: public Icontainer
{
public:
void addElem(Melem &elem) { elem.extra(); };
//*Now* we're implementing Icontainer::addElem
};