让我们说:
Class A
{
public:
virtual void print(){ std::cout<<" A "<<endl; }
}
Class B : public A
{
public:
virtual void print(int x){ std::cout<<" B "<<endl;}
}
我认为函数print的B类定义会隐藏A类的函数print。但是下面的代码工作并打印“A”
int main()
{
A * a = new B;
a->print();
return 0;
}
如果我像这样写主函数它不起作用:
int main()
{
B b;
b.print();
return 0;
}
我想知道的是...在我的第一个main()示例中,我有一个调用print()的B对象...不应该print()被隐藏并且有一个错误就像在第二个main()示例
答案 0 :(得分:6)
print()
中的成员函数B
未覆盖print()
中的A
,因为它具有不同的签名。因此,在您的第一个未编辑的print()
版本中调用main()
时,只有一个匹配的函数可以调用,正如用户juanchopanza所指出的那样:A::print()
。
编辑:总结:
多态行为:如果A::print()
和B::print()
具有相同的签名,只要您引用,就会在运行时选择相应的print()
对象通过指针或引用。
函数重载:由于类是作用域而函数不跨作用域重载,因此基类中的函数会被派生类中的同名函数隐藏。为此,您用来引用对象的类型的变量是重要的,不是对象本身的类型。因此,在第二个示例中,您会收到一个错误,即没有匹配的函数可以调用,但在第一个示例中,只有一个函数在范围内。
答案 1 :(得分:2)
这里的问题是名称查找。在A *a = new B; a->print()
之类的调用中,编译器查看a
的类型,即A*
,并在类A
中查找名为print
的成员函数。它找到它并且它调用它。类似地,对于B *b = new B; b->print();
,编译器在类B
中查找名为print
的成员函数;它找到print(int)
,不能在没有参数的情况下调用它。因为它在print
中找到了一个名为B
的函数,它会停止查找;它不会A
进入A::print()
。那是隐藏的名字。
这里的关键是名称查找以对象的声明类型开始;在这两个示例中,类型分别为A*
和B*
。查找不注意指针或引用指向或引用的事物的实际类型。
答案 2 :(得分:1)
这是因为两个print()
函数具有不同的签名。两个函数 - print()
和print(int)
被认为是不同的,并且不能被重载相互覆盖。
答案 3 :(得分:1)
派生类中的命名重载函数将这些函数隐藏在基类中。但是,您需要使用派生类接口来查看:
B b;
b.print(); // won't work
答案 4 :(得分:0)
检查您的班级定义; A
和B
中的打印功能具有不同的签名。当你打电话
a->print();
只有一个符合该签名的函数,即A::print()
。如果您从int
的定义中删除B
参数,则应该观察到您期望的行为。