如安在派生类中的埋没基类的虚拟重载函数
我建设了一个类,基类中有虚拟重载函数。我想在派生类中改写基类中的虚拟重载函数。代码如下:
#include <iostream.h>
class B {
private:
int nNumber;
public:
virtual void test() {
cout << "B::test()\n"; }
virtual void test(int x) {
nNumber = x; // 将传入的参数赋值给私有成员
cout << "B::test(int x)\n";
}
};
class D : public B {
public:
//test(void) 埋没 B::test(int)
virtual void test() {
cout << "D::test()\n";
}
};
void main(int argc, char* argv[])
{
D d; // 派生类的实例
d.test(); // OK
d.test(17); // 发生编译错误的代码行
}
基类中有两个重载的test函数。当我在派生类中改写个中的一个函数时,我以为别的一个应该在派生类中担任,但编译时呈现一下错误信息:
… C2660 : ”test” :function does not take 1 parameters
在不放弃多态行为的环境下,我能不能同时重载和改写某个函数?
很多C++措施员都对这个问题感想狐疑,为相识开这个惑点,有两个观念你必需要了然于心。一个是重载,一个是名字空间。从重载的视角看,你大概以为C++应该凭据你所想象的方法事情;也就是假如派生类只修改个中的一个重载函数的行为,那么别的一个应该凭据凡是的方法被担任。但从名字空间的角度看,当C++试图办理某个标记名时,它以由近到远的顺序举办搜索,它首先找当地变量,然后是类成员名,接着是基类名,全局变量……。一旦编译器理会了名字,它便终止理会进程。假如在差异的名字空间范畴遇到同一个标记名,那么它便没有了主意。在你的代码中,一旦编译器确命名字"test"呈此刻类D中,那么它的名字空间就为类D。岂论你挪用不带参数的test也好,照旧挪用带一个整型参数的test(17)也好,编译器都是遵循准这个法则来办理名字问题。对付有整型参数的test(int x)函数,一旦编译器确定函数名test保留在类D中,它便终止范畴探查,然后查找与参数匹配的函数。由于它没有在类D中找到带整型参数的函数,所以报错。此时编译器认为函数D::test(void)埋没了函数B::test(int)。你大概会问,为什么要按这种方法处理惩罚?问得好。想找到谜底,请参考Bjarne Stroustrup 的C++注释参考手册(Section 13.1)。简朴地说,在类条理深处搜索与某个签名匹配的重载函数比不搜索更大概导致杂乱。
那么如何办理上面呈现的问题呢?很容易。只要在派生类中建设另一个显式挪用基类的test函数即可,如:
class D : public B {
public:
virtual void test(int x) { B::test(x); }
……
};
这样,D就有了两个test函数,问题也办理了。 其实这个问题尚有别的一个解法:那就是在派生类中利用"using"要害字。如:
class D : public B {
public:
using B::test;
// 改写test
virtual void test() {
cout << "D::test()\n";
}
};
这个要害字将B::test带入类D中。它的利益是当类B扩展更多的test重载函数时,你不消再去重写类D的代码。这样省了许多事。只要你利用using要害字,那么就意味着所有重载的 B::test函数都进入类D而且获得担任。这种特性大概对付某些人来说是利益,而对付别的一些人来说是缺点,依赖于你要做什么工作。假如你想要向类D的用户埋没某些test函数,则可以用第一种要领(显式挪用基类),可能让你想要埋没的函数成为private 或 protected范例。假如你读过Scott的书《Effective C++》,还可以用第二种要领操作using要害字巧妙地担保基类的私隐。class B {
public:
func1();
func2(double d);
virtual test();
virtual test(int x);
};
// D 从B中奥秘派生
class D : private B {
public:
// 让所有 B::test 函数为 public范例
using B::test;
};
显然,当但愿完全埋没类B时,这个要领很有用,但假如想要果真B中的个体函数,则这个要领就不是那么好了。