[英]virtual function and derived class
让我首先向您展示简单的C ++代码示例。
#include <iostream>
using namespace std;
class Person{
string m_name;
public:
virtual void saySomething(){
cout << "I am a person.";
}
};
class Student:public Person{
public:
void saySomething(){
cout << "I am a student." << endl;
}
};
class CSStudent:public Student{
public:
void saySomething(){
cout << "I am a CS Student." << endl;
}
};
int main(){
Person* p = new Person();
Student* s = new Student();
CSStudent* c = new CSStudent();
((Student*)c)->saySomething();
return 0;
}
在我的示例中,Student是Person的派生类。 另外,CSStudent是Student的派生类。 我知道虚拟关键字可以确定它是否是派生类。
问题1
((学生*)c)-> saySomething();
为什么会收到“我是一名CS学生”? 我期望“我是学生”。 因为我只为Person指定了虚拟关键字。
问题2。
我看到了一个将虚拟关键字仅置于基本情况下的示例。 另外,我看到了一个将虚拟关键字应用于所有基本案例和派生类的示例。 两者有什么区别?
问题3。
虚拟功能是在运行时确定的。 非虚拟功能呢? 是在编译时确定的吗?
对于第一个问题,即使将c
CSStudent
基于同一基类的另一个类,它仍然是原始类(即CSStudent
)。 虚函数(几乎总是)是通过跳转表实现的。 因此, c
对象具有一个表,其中包含c
对象中实际函数的地址。 该表不会更改,因为您重新输入了类型。
对于第二个问题,没有区别。 如果在基类中将成员函数标记为virtual
,则在所有子类中也将其虚拟。 只是有些人也喜欢将子类中的功能标记为virtual
。 它实际上可能很好,因为这样您就不必检查基类即可查看哪些函数是虚拟的,哪些不是。
第三点。 是的,虚拟函数是使用如上所述的表在运行时计算的,而非虚拟函数是在编译时确定的。
问题1
((学生*)c)-> saySomething();
为什么会收到“我是一名CS学生”? 我期望“我是学生”。 因为我只为Person指定了虚拟关键字。
在C ++中,如果基类指定一个函数为virtual
,则对于具有相同签名的成员函数,您不需要任何派生类中的virtual
关键字。 您可以根据需要添加它(通常这样做是一种很好的做法),但这是可选的。
问题2。
我在网页上看到了一些示例,其中仅将虚拟关键字提到了基本情况。 另外,我看到了一些在所有基本案例和派生类中提及虚拟关键字的示例。 两者有什么区别?
如上所述:没有区别。 如果基类说具有特定签名的方法是虚拟的,则该方法也适用于所有派生类。
问题3。
虚拟功能是在运行时确定的。 非虚拟功能呢? 是在编译时确定的吗?
是。 如果您的saySomething()
函数不是虚拟的,则调用将在编译时解决,并且将其saySomething()
为Student*
意味着您将获得Student
版本的saySomething()
。
为什么会收到“我是一名CS学生”? 我期望“我是学生”。 因为我只为Person指定了虚拟关键字。
在C ++中,如果在基类中指定了virtual关键字,则该方法也将自动在任何子类中变为虚拟。 (我不会试图推测为什么C ++可以那样工作,但是确实可以)
我看到了一个将虚拟关键字仅置于基本情况下的示例。 另外,我看到了一个将虚拟关键字应用于所有基本案例和派生类的示例。 两者有什么区别?
在功能上没有区别。 从风格上讲,我认为后者在自我记录方面要好一些。
虚拟功能是在运行时确定的。 非虚拟功能呢? 是在编译时确定的吗?
正确。 特别是,将为非虚拟方法调用的方法实现将完全由调用该方法的指针类型确定,而不是通过对适当子类方法的动态查找来确定。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.