为什么基类指针(或引用)可以调用派生类的private虚函数

在基类中定义了public虚函数,在派生类中将其重写,但是设置为private,为什么通过基类指针仍然可以发生动态绑定调用派生类中的private虚函数?

例子如下:

class Base
{
public:
    // public虚函数
    virtual void Disp() { cout << "base.\n"; }
};
 
class Derived : public Base
{
private:
    // 重写基类虚函数,但是放在private中
    virtual void Disp() { cout << "derived.\n"; }
};
 
void main()
{
    Derived Dobj;
    Base *pBase = &Dobj;
    pBase->Disp();    // 显示的结果是派生类的虚函数被调用!
}
正确的解释:派生类中虚函数的访问权限是在编译阶段由基类确定的,在运行阶段不再检查访问权限,所以,虚函数的访问权限与派生类就没关系了。


更进一步的解释:当pBase->Disp()时,首先通过这个对象的vptr找到对应的vtable, 因为它实际上是Derived对象,所以找到的是Derived的虚表,所有的Derived对象都共用这个虚表。又因为是通过基类的指针调用的,编译器从Base的类型信息中查到Disp是虚表中的第一个entry, 而且这个函数的访问权限是public的,所以首先它让你调用,其次,从虚表第一个entry中取出的函数地址对应着Derived::Disp, 所以最后是Derived::Disp被调用,Derived::Disp在Derived中的访问权限在这里是无关的了,编译器根本不会费事去查询这一信息。甚至这一信息可能根本编译器也不知道。

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是定义 Shape 抽象类的代码: ``` class Shape { public: virtual float area() = 0; // 虚函数,用于计算面积 }; ``` 以下是从 Shape 派生出计算长方形面积的派生类 Rectangle 的代码: ``` class Rectangle : public Shape { public: Rectangle(float w, float h) : width(w), height(h) {} virtual float area() { return width * height; } private: float width, height; }; ``` 以下是从 Shape 派生出计算梯形面积的派生类 Trapezoid 的代码: ``` class Trapezoid : public Shape { public: Trapezoid(float u, float d, float h) : upper(u), lower(d), height(h) {} virtual float area() { return (upper + lower) * height / 2; } private: float upper, lower, height; }; ``` 以下是从 Shape 派生出计算圆形面积的派生类 Circle 的代码: ``` class Circle : public Shape { public: Circle(float r) : radius(r) {} virtual float area() { return 3.14159265358979323846 * radius * radius; } private: float radius; }; ``` 以下是程序中通过基类指针调用派生类中的虚函数的代码: ``` int main() { Shape *shapes[3]; // 定义基类指针数组 shapes[0] = new Rectangle(3, 4); shapes[1] = new Trapezoid(3, 5, 4); shapes[2] = new Circle(5); for (int i = 0; i < 3; i++) { cout << "Area of shape " << i + 1 << " is: " << shapes[i]->area() << endl; } return 0; } ``` 输出: ``` Area of shape 1 is: 12 Area of shape 2 is: 14 Area of shape 3 is: 78.53975 ``` ### 回答2: 抽象类 Shape 的定义如下: ```cpp class Shape { public: virtual double calculateArea() = 0; }; ``` 派生类 Rectangle、Trapezoid 和 Circle 构造如下: ```cpp class Rectangle : public Shape { private: double length; double width; public: Rectangle(double l, double w) : length(l), width(w) {} double calculateArea() override { return length * width; } }; class Trapezoid : public Shape { private: double base1; double base2; double height; public: Trapezoid(double b1, double b2, double h) : base1(b1), base2(b2), height(h) {} double calculateArea() override { return (base1 + base2) * height / 2; } }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} double calculateArea() override { return 3.14159 * radius * radius; } }; ``` 在主程序中,通过基类指针调用派生类中的虚函数,计算不同形状的面积: ```cpp int main() { Shape* shapes[3]; shapes[0] = new Rectangle(4, 5); shapes[1] = new Trapezoid(3, 5, 2); shapes[2] = new Circle(2); for (int i = 0; i < 3; i++) { cout << "Shape " << i + 1 << " 的面积为:" << shapes[i]->calculateArea() << endl; } for (int i = 0; i < 3; i++) { delete shapes[i]; } return 0; } ``` 以上程序中,通过基类指针数组 `shapes` 存储派生类对象的地址,通过循环遍历该数组,通过指针调用派生类虚函数 `calculateArea()` 来计算不同形状的面积,并输出结果。最后释放动态分配的内存。 ### 回答3: 抽象类 Shape 是一个用于计算面积的基类,其中包含一个纯虚函数 CalculateArea()。派生类 Rectangle、Trapezoid、Circle 是从 Shape 类派生的子类。 在程序中,我们可以通过使用基类指针调用派生类中的虚函数 CalculateArea(),以计算不同形状的面积。具体实现如下: ```cpp #include<iostream> class Shape { // 抽象类 public: virtual float CalculateArea() const = 0; // 纯虚函数 }; class Rectangle : public Shape { // 长方形派生类 private: float length; float width; public: Rectangle(float l, float w) : length(l), width(w) {} float CalculateArea() const override { return length * width; } }; class Trapezoid : public Shape { // 梯形派生类 private: float upperBase; float lowerBase; float height; public: Trapezoid(float uB, float lB, float h) : upperBase(uB), lowerBase(lB), height(h) {} float CalculateArea() const override { return (upperBase + lowerBase) * height / 2; } }; class Circle : public Shape { // 圆形派生类 private: float radius; public: Circle(float r) : radius(r) {} float CalculateArea() const override { return 3.14159 * radius * radius; // 这里假设圆周率为3.14159 } }; int main() { Shape* shape1 = new Rectangle(5, 7); // 创建长方形对象 Shape* shape2 = new Trapezoid(3, 7, 4); // 创建梯形对象 Shape* shape3 = new Circle(5); // 创建圆形对象 std::cout << "长方形的面积:" << shape1->CalculateArea() << std::endl; std::cout << "梯形的面积:" << shape2->CalculateArea() << std::endl; std::cout << "圆形的面积:" << shape3->CalculateArea() << std::endl; delete shape1; delete shape2; delete shape3; return 0; } ``` 在上述代码中,Shape 类中的 CalculateArea() 函数被声明为纯虚函数,因此 Shape 类成为了一个抽象类。Rectangle、Trapezoid、Circle 分别是 Shape 的派生类,并且都重写了 CalculateArea() 函数来计算各自形状的面积。 在主函数中,我们通过基类指针 shape1、shape2、shape3 分别指向 Rectangle、Trapezoid、Circle 类的对象。然后,通过调用基类指针虚函数 CalculateArea() 来计算相应形状的面积,并输出到控制台上。 最后,记得释放动态分配的内存。通过 delete 关键字释放 shape1、shape2、shape3 的内存空间。 运行程序后,将会得到长方形、梯形和圆形的面积输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值