Create a generic class with multiple inheritance input types

I want to create a father class that defines a generic virtual function that I can override in inheritance and, in every child, I want to change the input type. I tried to create a template function but I have seen that template functions don't compile if you try to made it virtual. I had an idea to template a variable in father class to don't have to use inheritance on this variable and then in children, do something in the override function with the specific version of the variable.

class a {
    virtual void doSomething() {
        //nothing in parent
    }

    template<typename T>
    T input;

    template<typename T>
    void SetInput(T i) {
        this->input = i;
    }
};

class b : a {
    virtual void doSomething() override {
        float test = this->input;
    }
};

class c : a {
    virtual void doSomething() override {
        char test = this->input;
    }
};

class d : a {
    virtual void doSomething() override {
        int test = this->input;
    }
};

void main(){
    std::vector<a> allNodes(3);
    b t1;
    t1.SetInput<float>(41.5f);
    c t2;
    t2.SetInput<char>('b');
    d t3;
    t3.SetInput<int>(3);
    allNodes[0] = t1;
    allNodes[1] = t2;
    allNodes[2] = t3;

    for (a node : allNodes) {
        node.doSomething();
    }
}

but from now on, this idea doesn't compile because it tells me that I need to define in father, in the SetInput() function, the type of the template when I will set it.

If you have some idea please tell me. Thx

Upvotes: 1

Views: 642

Answers (2)

Tiger Yu
Tiger Yu

Reputation: 764

This is a typical question confuses lots of people, and it can be done very simply by these steps:

  1. Make an interface that contains the common functions you want to call without knowing the object type, I named it Doable

  2. Create a template class derived from the interface Doable, I named it MyType, which contains the templated data member and operations get() & set(). IMPORTANT: also overrides pure virtual functions in Doable

  3. Specialize the template's function dosomething() for all data types you want to use within your program.

== BINGO ==

#include <iostream>
#include <string>
#include <vector>

class Doable {
public:
    virtual ~Doable() = default;
    virtual void dosomething() = 0;
};

template <typename T>
class MyType : public Doable {
public:
    T data_;
    void set(const T& d) {
        data_ = d;
    }
    T get() const {
        return data_;
    }
    void dosomething() override { }
};


template<>
void MyType<int>::dosomething() {
    std::cout << "int: " << data_ << std::endl;
}

template<>
void MyType<char>::dosomething() {
    std::cout << "char: " << data_ << std::endl;
}

template<>
void MyType<float>::dosomething() {
    std::cout << "float:" << data_ << std::endl;
}

int main(){
    std::vector<std::unique_ptr<Doable>> a;
    std::unique_ptr<MyType<float>> b1(new MyType<float>);
    b1->set(41.5f);
    a.push_back(std::move(b1));

    std::unique_ptr<MyType<char>> b2(new MyType<char>);
    b2->set('b');
    a.push_back(std::move(b2));

    std::unique_ptr<MyType<int>> b3(new MyType<int>);
    b3->set(3);
    a.push_back(std::move(b3));

    for (auto& ptr : a){
        ptr->dosomething();
    }
}

The output is:

float:41.5
char: b
int: 3

Upvotes: 1

RedFog
RedFog

Reputation: 1015

  1. a variable template as non-static member of class is not allowed, you must use class template.
  2. virtual function template is also not allowed. you must call a non-template virtual function by a non-virtual function template.

so you should use both a common base class to be a polymorphic class and a class template to store value with different types:

template<typename T>
class B;

class A{
public:
    virtual ~A() = default;
    template<typename T>
    void set(T a){
        dynamic_cast<B<T>*>(this)->input = a;
    }
    template<typename T>
    T get() const{
        return dynamic_cast<B<T>*>(this)->input;
    }
    virtual void dosomething() = 0;
};

template<typename T>
class B : public A{
public:
    T input;
    virtual ~B() = default;
};

class C : public B<float>{
public:
    virtual ~C() = default;
    virtual void dosomething() override{
        std::cout << input << std::endl;
    }
};

class D : public B<int>{
public:
    virtual ~D() = default;
    virtual void dosomething() override{
        std::cout << input << std::endl;
    }
};

int main(){
    std::vector<A*> a;
    C* c = new C;
    c->set(12.3f);
    a.push_back(c);
    D* d = new D;
    d->set(1);
    a.push_back(d);
    for (auto ptr : a){
        ptr->dosomething();
    }
    // output:
    // > 12.3
    // > 1
    delete c;
    delete d;
}

Upvotes: 0

Related Questions