Reputation: 11
First of all sorry for the title being confusing. Here's my OOP setup. I have base class Base, and two pure virtual functions add and multi. Then I have derived classes D1 and D2 and I implement the add and multi functions. I want to have a template function, that can have the flexibility that can switch between D1 D2 and calling add or multi functions. I googled around and someone people saying I should use function pointers but some others say it does not work with pure virtual functions.
class Base
{ double data; //data member
Base(double d):data(d){};
virtual double add() = 0;
virtual double multi() = 0;
}
class D1::public Base
{ D1(double d): Base(d) {}; //calling base class constructor
double add() {return data+1;} ;
double multi() {return data*2;} ;
}
class D2::public Base
{ D2(double d): Base(d) {}; //calling base class constructor
double add() {return data+3;} ;
double multi() {return data*4;} ;
}
//now I want to have a template function that give me flexibility to construct D1 or D2 and calling add or multi.
template <typename T, typename F>
void testFun(double num)
{ T tmp(num); //create object either D1 or D2;
cout << T->F() << endl; //calling either add or multi;
}
int main()
{ testFun<D1, D1.add()>(double x = 5);
//i know passing in D1.add() is wrong i don't know how to fix, hopefully you know what I am trying to achieve
return 0;}
Any help will be appreciated. Thank you guys.
Upvotes: 1
Views: 519
Reputation: 169318
There's nothing about virtual member functions that makes pointers to member functions not work. You can invoke a pointer to a pure virtual function if the object being invoked on is a pointer/reference to an object that has an actual implementation.
It looks like you're getting tripped up on the syntax of exactly how to pass a pointer-to-member-function in the first place.
Also note that virtual dispatch wouldn't even be used here since the type of object being used is known at compile time.
template <typename T>
void testFun(double num, double (T::*fn)())
{
T tmp(num);
std::cout << (tmp.*fn)() << std::endl;
}
Here, fn
is a pointer to a member function of T
that accepts no arguments and returns a double
value. You can invoke it like so:
testFun<D1>(5, &D1::add);
Note some other errors with the example code you've given:
::
when you should use :
. For example: class D1 : public Base
.class
but never specify an access modifier, which means all members are implicitly private
. For the purposes of the demo, changing them to struct
(which defaults to public
access) fixes this.Here is a demo of the working code.
Just for the sake of completeness, here is a demo showing that you can use a pointer to a pure-virtual member function to invoke on a reference/pointer to a derived type. The code has to be adjusted to use a D1
or D2
object through a reference of Base
for the dispatch to be dynamic. This example looks like:
template <typename T>
void testFun(double num, double (Base::*fn)())
{
T tmpConcrete(num);
Base & tmp = tmpConcrete;
std::cout << (tmp.*fn)() << std::endl;
}
int main() {
testFun<D1>(5, &Base::add);
}
(Of course, here it's a bit silly to use a pointer to a Base
member when the generic code knows what T
is, but it proves the point that it's possible.)
Upvotes: 2