2012-02-11 82 views
1

虽然通过STL源(Dinkumware的,SGI,STLport的,等..),并试图让他们实现选择感(它会很好),我碰到的东西来了,我觉得挖有点奇怪或而从来没有碰到过。继承,伪多态性

通常,当一个人希望在派生类重载一个成员函数,你会在前面加上虚拟关键字基类成员函数签名,然而在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:这也似乎没有被类模板太工作。

“问候

回答

2

没有virtual关键字 - 重新定义函数时,你是隐藏了超级的功能。

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

虽然,因为它未声明virtual,你会看到这种影响只有当你从typeB变量调用func()A类型的变量,其保持B,将调用A的FUNC()。

A *a = new B; 
a->func() 

将调用第一个[A]的方法。

要调用B的方法,你需要的类型是B

B *b = new B; 
b->func() 
2

B<T>::func构件简单地shadowsA<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::rdbufhides its ancestor's method by that name和实际上改变它的返回类型。

+0

啊谢谢,你每天都会学到新的东西!现在你提到它确实有道理。 – rtlayzell 2012-02-11 11:55:18

1

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

这在几个地方进行生产,从一个函数,它本质上是平凡转发到另一个功能(至少,这些是我能想到的地方)不同的返回类型。这只是为了让用户的生活变得更加简单,虽然它比其他任何事情都更令人困惑。我能想到的例子(例如流中的rdbuf()函数)应该创建一个不同的名称。

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,它会调用上的指针的类型的功能。