请查看以下代码清单:
#include <iostream>
using namespace std;
class Base {
public:
virtual void Message() = 0;
};
class Intermediate : public Base {
};
class Final : public Intermediate {
void Message() {
cout << "Hello World!" << endl;
}
};
int main() {
Final final;
/* Wont work (obviously):
Final* finalPtr = &final;
finalPtr->Message();
*/
// Works:
Intermediate* finalPtr = &final; // or Base* finalPtr = &final;
finalPtr->Message();
return 0;
}
请注意以下事项:
问题: 如果您运行该程序, finalPtr-&gt; Message(); 行成功调用最终的 message()功能实现的私有即可。这是怎么发生的?基类是否覆盖或忽略派生类的访问限制?
相关问题: 关于上面的(2.),定义中级类的正确方法是什么?是否需要从基类重新声明纯虚函数 message(),同时请注意中级类不是为了提供实现。
注意:代码已使用Digital Mars Compiler(dmc)和Microsoft的Visual Studio编译器(cl)进行测试,并且在两者中都运行良好
答案 0 :(得分:4)
这是怎么发生的?基类是否覆盖或忽略派生类的访问限制?
使用公共继承,Base类的所有公共成员都将成为派生类的公共成员。是的Message()
是Intermediate
中的公共功能。
在基类(Intermediate
)指针上调用该函数,该函数在基类中是公共的。动态调度(即对Derived类函数的实际调用)仅在运行时发生,因此可以正常工作。
上述原因是在运行时,访问说明符没有意义,访问说明符规则只在编译时解析并生效。
如果在派生类指针上调用该函数,那么在编译时,编译器会检测到Message()
中private
被声明为Final
,因此它会给出错误。
从Abstract类派生时,派生类必须为 ALL 提供Base类的Pure虚函数的定义,否则将导致Derived class也是一个抽象类。
这里Intermediate
类是一个抽象类,只要你不需要创建这个类的对象,它就可以正常工作。请注意,您可以创建指向Abstract类的指针。
答案 1 :(得分:1)
在C ++中,虚拟和访问说明符是互斥的。这就是为什么在C ++中,可以缩小虚拟方法的访问权限,而在C#或Java中则不可能。
当您尝试通过基类指针访问虚函数时,编译器会编译代码,因为基类的虚函数是公共的。
在您的注释代码中,具有受限访问权限的虚拟函数通过Final类指针调用。因此编译错误。