我在同一个问题上已经完成了一些以前的帖子,但我找不到任何令人满意的答案。
为什么基类指针始终指向基类,即使它保存派生类对象的地址?我知道,由于这个原因,virtual
关键字出现在图片中,但我无法弄清楚为什么基类指针始终指向基类,即使它保存派生类的地址。有人可以解释一下吗?
class base
{
public:void fn()
{
cout << "I am in base" << endl;
}
};
class derived : public base
{
public:void fn()
{
cout << "I am in derived"<< endl;
}
};
int main()
{
base *p; // creating pointer object for base class
derived obj; // creating object for derived class
p=&obj; // storing object of derived class in pointer
p->fn(); // If pointer has address of derived class object
// then why still it print base class function
// why we need to use virtual keyword to print
// derived class function?
}
答案 0 :(得分:3)
派生类的对象始终在其中的某处包含基类类型的对象。这被称为“基类子对象”。如果p
的类型为base*
,那么当p
设置为指向derived
类型的对象时,它实际上设置为指向base
子对象那个derived
对象。
此行为确保即使指针实际指向派生类的对象,也可以从指针调用基类非静态成员函数。因此,实现不会 在运行时查找p
是指向完整的base
对象还是完整的derived
对象;无论如何,它仍然指向一个base
对象(可能只是一个基类子对象)。
为了确保即使您使用指向基类的指针调用派生类的函数实现,编译器也必须在运行时生成查找的附加代码,无论是否指针指向完整的base
对象或完整的derived
对象。如果要强制它执行此操作,请标记函数virtual
。如果没有,那么当您不需要时,C ++不会强迫您支付虚拟呼叫的费用。
答案 1 :(得分:0)
为什么基类指针始终指向基类,即使它保存派生类对象地址?
原因是编译器忽略指针p
的内容,并选择与类型<匹配的成员函数(如果未声明virtual
) / em>指针。
答案 2 :(得分:0)
因为你没有让fn
虚拟。由于p
指向base
,因此调用base的方法。如果您想要具有其他行为,请将base中的fn
声明为虚拟。
设置p
时,编译器无法知道p指向derived
。在这个简单的情况下它可以,但在其他情况下,例如当调用接受指向基础对象的指针的函数时,它不能:
考虑简单的功能
void doStuff(Base* base)
{
base->fn();
}
编译doStuff
时,编译器无法知道最初指向derived
对象的基础。所以为了保持一致,最好不要使用这个类型在给出的简单案例中已知的事实。
要跟踪指针所指向的“{1}”类型,可以将所考虑的函数声明为 virtual 。这通常会为从base
派生的所有类添加一个不可见的指针。该指针指向 vtable ,而 vtable 又包含指向所有虚拟方法的指针。
为什么默认情况下这些方法不是虚拟的?因为它添加了一个不可见的成员,