虚函数 父类指针指向子类
时间: 2024-09-18 17:05:32 浏览: 12
虚函数是一种特殊类型的成员函数,在C++中,当我们在父类的指针或引用上声明它为虚函数时,即使该指针实际上指向的是子类的对象,调用这个函数时会根据实际对象的类型动态地调用子类的实现。这种机制实现了动态绑定,也称为晚期绑定或运行时多态。
举个例子:
```cpp
class Base {
public:
virtual void display() { // 虚函数声明
cout << "Base class" << endl;
}
};
class Derived : public Base {
public:
void display() override { // 子类重写虚函数
cout << "Derived class" << endl;
}
};
int main() {
Base* basePtr = new Derived(); // 父类指针指向子类对象
basePtr->display(); // 运行时调用Derived的display()
delete basePtr; // 删除对象
return 0;
}
```
在这个例子中,虽然`basePtr`是一个`Base`类型的指针,但我们通过它调用`display()`时,实际上是调用了`Derived`类的版本,这就是虚函数在父类指针下工作的原理。
相关问题
父类是虚类,父类中有一个函数a调用了父类的虚函数,在子类中重写了这个虚函数,父类指针指向子类对象时,调用函数a出现:引发异常,读取访问权限冲突
在父类是虚类的情况下,当父类中的函数a调用了父类的虚函数,并且在子类中重写了这个虚函数时,如果父类指针指向子类对象,调用函数a可能会引发异常,出现访问权限冲突的情况。
这是因为在C++中,虚函数的调用是通过虚函数表来实现的。当父类指针指向子类对象时,调用函数a时会先在父类的虚函数表中查找对应的虚函数,然后调用该虚函数。但是由于子类重写了父类的虚函数,子类的虚函数表中的对应位置存储的是子类的虚函数地址。因此,当父类指针指向子类对象时,调用函数a时会去父类的虚函数表中查找虚函数地址,但实际上调用的是子类的虚函数。
这样就会导致访问权限冲突的问题。因为父类中的函数a可能依赖于父类的虚函数的实现,而子类重写了这个虚函数,可能会改变虚函数的行为,导致函数a的逻辑出现问题。
为了避免这种访问权限冲突的问题,可以在父类中将虚函数声明为纯虚函数,即在函数声明后面加上`= 0`。这样父类就成为了抽象类,不能直接实例化对象,只能作为基类被继承。子类必须实现纯虚函数,否则子类也会成为抽象类。
示例代码如下所示:
```cpp
class Base {
public:
virtual void func() = 0; // 纯虚函数
};
class Derived : public Base {
public:
void func() override {
// 子类实现纯虚函数
// 具体的实现逻辑
}
};
int main() {
Base* ptr = new Derived(); // 父类指针指向子类对象
ptr->func(); // 调用虚函数
delete ptr;
return 0;
}
```
这样,父类指针指向子类对象时,调用函数a就不会出现访问权限冲突的问题了。
父类指针指向子类对象的虚函数表在编译时期与运行时期发生了哪些变化?
在编译时期,编译器会根据父类指针的声明类型来确定虚函数表的地址,并将其存储在父类指针中。这个地址指向的是父类的虚函数表,也就是说,编译时期确定的虚函数调用地址都是父类的虚函数地址。
在运行时期,当父类指针指向子类对象时,编译器会根据对象的实际类型(即子类类型)来重新计算虚函数表地址,并将其存储在父类指针中。这个地址指向的是子类的虚函数表,也就是说,运行时期确定的虚函数调用地址都是子类的虚函数地址。
因此,当使用父类指针调用虚函数时,会根据运行时期确定的虚函数表地址来调用相应的虚函数,从而实现了多态性。这也是C++中面向对象编程的一个重要特性。