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.
Related
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.
How do I ensure my derived class implements at least one of two chosen methods in the base class?
class base {
public:
virtual int sample()=0;
virtual Eigen::VectorXf sample()=0;
};
class Derived : Base {
int sample() override {return 1;}
}
This code returns an error, as the sample method is not implemented with the VectorXf return type. However, my intention is that only one of these need to be implemented. The only reason they are seperate in the base class is that they have different return type. How can I do this in C++?
Overloading by return type is not possible. You may use std::variant instead:
#include <variant>
class Base {
public:
virtual std::variant<int, Eigen::VectorXf> sample()=0;
};
class Derived : public Base {
std::variant<int, Eigen::VectorXf> sample() override {return 1;}
};
If one is restricted to C++11, then there are many alternatives.
Implement and use something like variant: a class that has a enumerator selecting between two active types, and a union to contain these types.
Use Boost variant.
std::pair
Implement a hierarchy of classes (a simplification of std::any), and return on the right pointer to object:
class AbstractBase {
public:
virtual ~AbstractBase() = 0;
template <class T>
const T* get() const;
};
template <class T>
class ValueWrapper : public AbstractBase {
public:
ValueWrapper(const T& value) : m_value(value) {}
const T & getValue() const { return m_value; }
private:
T m_value;
};
template <class T>
inline const T * AbstractBase::get() const {
auto child = dynamic_cast<ValueWrapper<T> const*>(this);
return child ? &child->getValue() : nullptr;
}
class Base {
public:
virtual std::unique_ptr<AbstractBase> sample()=0;
};
The question is, why would you need this?
I've got class with template and some classes inherit from him.
We want to create instance of the father class without declaring its template type, and call a function returning the template type.
Example:
class FatherWrap {
virtual ~FatherWrap() = default;
};
template<typename T>
class FatherClass : public FatherWrap
{
virtual T getValue();
};
class SonClass1 : public FatherClass<int>
{
int getValue() override;
};
class SonClass2 : public FatherClass<string>
{
string getValue() override;
};
int main()
{
FatherWrap* ch = new SonClass1();
T a = ch->getValue; // What to do instead of T.
}
Let's say you have:
An unparameterized (no template) base class B
An intermediate template class I<T> inheriting from B
Some derived classes D1, D2, etc. each of which inherits from a specialization of I
You want to write some code in terms of B. You can do that--but you have to limit yourself to using the API that B defines. The methods of B can be virtual, and the implementations/overrides of those methods in I<T> and Dx can use the type T, but those types can't be exposed to a component the only knows about B.
If you want to write some logic that uses T, then that logic needs to be either in a method of I<T>, or in a template function that is itself parameterized with a class type:
template<class U>
U someTypeSpecificLogic(I<U> intermediate) {
// can call methods that accept/return U here
}
You can't write logic in terms of B that depends on the type T because that type is only defined for the subclass I<T>. Consider that the B you have be a different subclass of B and not an I<T> at all.
You could skip the FatherWrap entirely and make the base class return a variant:
struct FatherClass : FatherWrap {
virtual std::variant<int, std::string> getValue();
};
struct SonClass1 : FatherClass {
std::variant<int, std::string> getValue() override {
return "some text";
}
};
struct SonClass2 : FatherClass {
std::variant<int, std::string> getValue() override {
return 95;
}
};
Alternatively, you could template any code that uses SonClass:
struct SonClass1 { // no parent.
std::string getValue() {
return "some text";
}
};
struct SonClass2 { // no parent.
int getValue() {
return 95;
}
};
template<typename T>
void useSonClass(T& son) {
// value may be int or string.
auto value = son.getValue();
}
int main() {
SonClass1 sc1;
SonClass2 sc2;
useSonClass(sc1);
useSonClass(sc2);
}
If you want to contain it, just use a variant:
int main() {
std::variant<SonClass1, SonClass2> sc = SonClass2{};
std::visit(
[](auto& sc) { useSonClass(sc); },
sc
);
}
I'm trying to make an abstract class, and one of the methods that its children must override should return an instance of the child class.
class JsonSerializable {
public:
virtual <child_of_JsonSerializable> fromJson(string jsonStr) const = 0;
};
class ConcreteSerializable : public JsonSerializable {
public:
ConcreteSerializable fromJson(string jsonStr) const {
return ConcreteSerializable();
}
};
I tried using templates following this answer, but I get an error that templates may not be virtual.
Is there a way to do what I'm looking for without using raw pointers as the return type?
You cannot create an object of an abstract type. And because you cannot create such an object, you also cannot return it. This is the reason why all examples returning a base/derived object, always return a pointer or some reference to the base class
struct B {
virtual B *fromJson(const std::string &jsonStr) const = 0;
};
struct D : public B {
D(const std::string &jsonStr);
D *fromJson(const std::string &jsonStr) const;
};
D *D::fromJson(const std::string &jsonStr) const
{
return new D(jsonStr);
}
Are you trying to implement something that historically was done using CRTP?
struct Interface {
virtual Interface *inflate(std::string const &json) = 0;
virtual ~Interface() {}
};
template<typename Child> struct Base: public Interface {
Interface *inflate(std::string const &json) { return new Child(json); }
};
struct Child: public Base<Child> {
Child(std::string const &json);
};
As far as I know, templated virtual functions aren't allowed/possible due to the undefined size of the vtable.
On the other hand, virtual functions inside a class template which don't use the template type seem to be allowed, right?
What about a virtual function that doesn't use the template type as parameter or return type but works on data of the template type? Would that be valid C++?
I have already done some testing and it seems to work.
My Code looks like this:
(Note: For reasons of readability this is only the basic structure, not the real code).
template<typename T>
class Base {
public:
virtual bool compare(void) {
// Basic implementation
return ((value1 + value2) < value3);
}
protected:
T value1, value2, value3;
}
/**
* Derived from Base<ComplexClass> where
* ComplexClass is a Class providing
* a int Value through .getInt()
**/
class Derived : Base<ComplexClass> {
bool compare(void) {
return ((value1.getInt() + value2.getInt()) < value3.getInt());
}
}
main {
Base<int> *intBase = new Base<int>();
Base<double> *doubleBase = new Base<double>();
Base<ComplexClass> *complexBase = new Derived();
intBase->compare(); // Should call base function
doubleBase->compare(); // Should also call base function
complexBase->compare(); // Should call the compare function of Derived
}
As far as i can tell this works like I excepted. Is this just a lucky coincidence or is this valid/good C++ style?
If it's valid, could someone please explain what's happening inside and why some people say it's forbidden/bad practice to derive from class templates and use virtual functions inside of class templates?
Thank you in advance!
PS: I know something similar could have been done by template specialization but I'd like to know if it's also possible this way.
Q As far as I know, templated virtual functions aren't allowed/possible due to the undefined size of the vtable.
A You can have virtual function in class templates.
Example code that compiles and links:
template <typename T>
struct Base
{
virtual T doSomething(T const& in) = 0;
Base(T const& data) : data_(data) {}
T data_;
};
struct Concrete : public Base<int>
{
Concrete(int d) : Base(d) {}
virtual int doSomething(int const& in)
{
return data_*in;
}
};
int main()
{
Concrete a(20);
int b = a.doSomething(10);
}
Q On the other hand, virtual functions inside a class template which don't use the template type seem to be allowed, right?
A The virtual functions of a class template can use anything -- not restricted to not using the template tye.
My example should make that clear.
Q What about a virtual function that doesn't use the template type as parameter or return type but works on data of the template type? Would that be valid C++?
A Yes, it will.
Again, my example should make that clear.
EDIT: Extended example
template <typename T>
struct Base
{
virtual T fun1(T const& in) = 0;
virtual T fun2(int in) = 0;
virtual int fun3(T const& in) = 0;
virtual int fun4(int in) = 0;
Base(T const& data) : data_(data) {}
T data_;
};
struct Concrete : public Base<int>
{
Concrete(int d) : Base(d) {}
virtual int fun1(int const& in)
{
return data_*in;
}
virtual int fun2(int in)
{
return fun1(in);
}
virtual int fun3(int const& in)
{
return fun1(in);
}
virtual int fun4(int in)
{
return fun1(in);
}
};
int main()
{
Concrete a(20);
int b = a.fun1(10);
int c = a.fun2(10);
int d = a.fun3(10);
int e = a.fun4(10);
}
This is perfectly valid. However, here you can have the same behaviour with specialization or just overloading, e.g.
template<typename T>
struct Base
{
bool compare() const { return val(value1) + val(value2) < val(value3); }
protected:
T value1, value2, value3;
private:
template<typename U>
static U val(U a) { return a; }
static int val(const ComplexClass& a) { return a.getInt(); }
};
Better keep virtual functions for when it's really needed.
And try to gather as much as possible shared code in a single place, minimizing what is to be specialized.