6

在 C++ 中可以将函数参数定义为不止一种类型吗?

#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);
}

我想用不使用宏的东西来改变注释之间的代码。我不会强制转换指针,因为我想保持类型安全。我什至不会在 C/D 和 A/B 之间引入另一个类,因为实际上我的类层次结构比代码中显示的要复杂一些,并且不希望重新设置从 A 或 B 派生的所有类

4

3 回答 3

4

就像@Torsten 建议的那样,一个可能的解决方案是使用函数模板,以便您可以传递任何类型的参数。但是,一个简单的模板将适用于提供适当成员的任何类型(在本例中为printAand printB),因此以下函数模板

template <typename T>
void printAll(T const & t)
{
    t.printA();
    t.printB();
}

将使用以下类型

struct Foo
{
    void printA() const { std::cout << "FooA\n"; }
    void printB() const { std::cout << "FooB\n"; }
}

printAll(Foo());

即使Foo不是派生自Aor B。这可能是可取的,但如果您真的想强制执行参数必须是 aA和 a的事实B,您可以在函数中使用静态断言来检查:

#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();
} 

另一种解决方案是std::enable_if仅在模板参数确实是Aand的派生类时才使用定义函数模板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();
}

注意:static_assert和是 C++11 特性enable_ifis_base_of如果您正在使用 C++03,您可以在各种 Boost 库中找到等价物。

于 2012-07-18T11:53:17.997 回答
3

模板版本只会选择传递给函数的类型:

template < class T >
void printall( T* t )
{
   t->printA();
   t->printB();
}
于 2012-07-18T10:57:37.513 回答
1

托斯滕是对的。相反,如果在运行时看起来像“后期绑定”,您可以使用函数指针。你可以在这里找到一个清晰的例子。

于 2012-07-18T11:01:15.800 回答