Reputation: 11
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
Reputation: 764
This is a typical question confuses lots of people, and it can be done very simply by these steps:
Make an interface that contains the common functions you want to call without knowing the object type, I named it Doable
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
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
Reputation: 1015
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