继承,伪多态

时间:2012-02-11 11:36:16

标签: c++ inheritance stl polymorphism metaprogramming

虽然通过STL源(DinkumWare,SGI,STLport等)挖掘并尝试理解他们的实现选择(它进展顺利),但我发现了一些我觉得有点奇怪或者我从未跑过的东西进入之前。

通常,当希望重载派生类中的成员函数时,您将使用virtual关键字预先添加基类成员函数签名,但是在STL源的各个点处,情况并非如此。

这是我在STL实现中看到的缩减版本:

template <typename T> class A {
public:
    void func( ) { std::cout << "inside A func( )" << std::endl; }
};

template <typename T> class B : public A<T> {
public: 
    void func( ) { std::cout << "inside B func( )" << std::endl; }
};

编译器似乎很好用这个伪多态,因为我期待一个错误的东西:

error C2535: 'void B<T>::func(void)': member function already defined or declared

有人会善意地解释这里发生了什么吗?

PS:这似乎也可以在没有类模板的情况下工作。

“的问候

4 个答案:

答案 0 :(得分:2)

B<T>::func成员只需shadows A<T>::func。当您致电p->func() A<T> *p指向B<T>时,会调用A<T>::func,因此没有多态性。

#include <iostream>

struct A
{
    void func() { std::cout << "Hello!\n"; }
};

struct B : public A
{
    void func() { std::cout << "Goodbye!\n"; }
};

int main()
{
    B b;
    A *p = &b;

    p->func();
    b.func();
}

Demo

在C ++标准中,至少有一个地方可以利用此隐藏/名称隐藏:std::ifstream::rdbuf hides its ancestor's method by that name并实际更改其返回类型。

答案 1 :(得分:2)

没有virtual关键字 - 重新定义函数时,您隐藏了超级函数。

在您的情况下,通过重新定义func(),您告诉编译器B有一个新函数,它与A不同。

但是,因为它未声明为virtual,所以只有从type func()变量调用B时才会看到此影响。保存A的{​​{1}}类型的变量将调用B的func()。

A

将调用第一个[A *a = new B; a->func() ]方法。

要调用A的方法,您需要类型为B

B

答案 2 :(得分:1)

显然没有错误,因为这些函数只是重载:A::func()有一个签名,将A对象(引用或指针)作为第一个参数,而B::func()有签名将B对象作为第一个参数。也就是说,这只是使用不同参数但函数名称重载两个函数。

这是在一些地方完成的,以便从一个函数产生不同的返回类型,这个函数基本上很容易转发到另一个函数(至少,这些是我能想到的地方)。这只是为了让用户的生活更轻松,尽管它实际上比其他任何东西都更容易混淆。我能想到的例子(例如流中的rdbuf()函数)应该创建一个不同的名称。

答案 3 :(得分:1)

这是可接受的代码,B<T>::func只是隐藏A<T>::func

A<int> a;
B<int> b;
a.func(); // inside A
b.func(); // inside B

A<int> *const pA = new B<int>();
pA->func(); // inside A

通过多态类型调用func时,它会调用指针类型的函数。