It is possible in C++ define a function argument to be of more than one type?
#include <iostream>
using namespace std;
class A {
public:
void PrintA() { cout << "A" << endl;}
};
class B {
public:
void PrintB() { cout << "B" << endl;}
};
class C: public A, public B {
public:
C(){;}
};
class D: public A, public B {
public:
D(){;}
};
///
void __printall__(A*a, B*b){
a->PrintA();
b->PrintB();
}
#define printall(a) __printall__(a,a)
///
int main(int argc, char *argv[]){
C c;
D d;
printall(&c);
printall(&d);
}
I want to change the code between the comments with something not using macros. I would not force the pointers cast because I want to preserve the type safety. I would not even introduce another class between C/D and A/B because actually my class hierarchy is a bit more complex of that shown in the code, and it is not desirable to rebase all the class that derive from A or B
Like @Torsten advised, a possible solution is to use a function template so that you can pass any type of arguments. However, a simple template will work with any type that provides the appropriate members (in this case printA
and printB
), so the following function template
template <typename T>
void printAll(T const & t)
{
t.printA();
t.printB();
}
will work with the following type
struct Foo
{
void printA() const { std::cout << "FooA\n"; }
void printB() const { std::cout << "FooB\n"; }
}
printAll(Foo());
even though Foo
does not derive from A
or B
. This might be desirable, but if you really want to enforce the fact that the argument must be a A
and a B
, you can use a static assertion in your function to check that:
#include <type_traits>
template <typename T>
void printAll(T const & t)
{
static_assert(std::is_base_of<A, T>::value && std::is_base_of<B, T>::value,
"T must be derived from A and B");
t.printA();
t.printB();
}
An alternate solution would be to use std::enable_if
to define the function template only when the template parameter is indeed a derived class of A
and B
:
template<
typename T ,
typename = typename std::enable_if<
std::is_base_of<A, T>::value &&
std::is_base_of<B, T>::value
>::type
>
void printAll(T const & t)
{
t.printA();
t.printB();
}
N.B: static_assert
, enable_if
and is_base_of
are C++11 features. If you are working with C++03, you can find the equivalent in various Boost libraries.
a template version will just pick the type, that is passed to the function:
template < class T >
void printall( T* t )
{
t->printA();
t->printB();
}
Torsten is right. Instead, if are looking something like "late binding" at run-time you could use a function pointer. You can find a clear example here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With