c++期末考试学习资料

C++ Final exam study material

本文关键字:学习资料 考试 c++      更新时间:2023-10-16

我一直在做这个问题,为我即将到来的c++期末考试做准备。

// What gets printed?
#include <iostream>
using namespace std;
class A {
  public:
    A(int a = 5) : i(a) { cout << "A" << endl; }
    void foo() { cout << "this.i " << i << endl; }
    virtual void print() const { cout << i << " in A" << endl; }
  protected:
    int i;
};
class B : public A {
  public:
    B() : A(1) { cout << "B default" << endl; }
    void foo() { cout << i << " in B" << endl; }
    void print() const { cout << i << " in B" << endl; }
};
int main() {
  A *pa;
  B b;
  pa=&b;
  pa->foo();
  pa->print();
  return 0;
}

,其输出为:

A
B default
this.i 1
1 in B

我明白,A被打印是从超类A调用B的构造函数,我明白,使指针*pa点在&b使其访问foo的基类方法,但它是如何在B::print()中打印值而不是A::print() ?

这是因为您在b中重写了print(),并且由于foo()在类A中未定义为虚函数,因此调用了类A中的foo()。

由于B派生自A,因此每个B 都是A。因此,pa可以指向A类型或任何派生类型的对象。但是对象的类型没有改变,所以b仍然是B类型,并且行为也是这样。唯一的限制是,由于它是由指向A的指针引用的,因此您只能引用在基类A中声明的方法和成员变量。

关于为什么 c++以这种方式工作的解释,请查看vtable s的讨论。

virtual void print()
函数前面的虚字使多态发挥了它的魔力。当派生类实现了在基类中声明为虚函数的函数时,派生类的实例将调用该函数,而不是调用基类函数。

您创建了派生类B的实例,B有一个名为print()的成员函数,它将被调用。

pa->foo();

pa->print();

是由一个简单的事实引起的:

指针的类型指示编译器如何解释在特定地址找到的内存,以及该解释应该跨越多少内存

,出自书 c++对象模型内部。

换句话说,当编译器试图翻译pa->foo()这行代码时,他只知道pa是a类的指针,而foo是a类的函数。虽然我们实际上知道pa指向B类的内存块,但编译器不知道也不可能知道这个事实。他只是将pa解析为a类的指针,并找到a对函数foo的定义。pa->print()的神奇之处在于c++的虚函数实现。对于普通函数,编译器只解析它的名称并跳转到该函数的起始地址。然而,对于虚函数,编译器将首先从指针pa所指向的内存中查找vptr指针,并解析vptr以查找print函数的正确定义。因为这次编译器从内存中读取vptr,而内存实际上属于B类,所以会调用B的print。
下面是另一个例子来说明它:

// What gets printed?
#include <iostream>
using namespace std;
class A {
  public:
int b;
    A(int a = 5) : i(a) { 
      b = 42;
  cout << "A" << endl; 
    }
    void foo() { cout << "this.i " << i << endl; }
    virtual void print() const { cout << i << " in A" << endl; }
   protected:
     int i;
 };
 class B : public A {
   public:
 int b;
     B() : A(1) { 
       b = 43;
   cout << "B default" << endl; }
     void foo() { cout << i << " in B" << endl; }
     void print() const { cout << i << " in B" << endl; }
 };
 int main() {
   A *pa;
   B b;
   pa=&b;
   cout << pa->b << endl;
   cout << b.A::b << ", " << b.b << endl;
   //pa->foo();
   //pa->print();
   return 0;
 }

输出为

A
B default
42
42, 43
顺便说一下,虚函数机制只对指针或引用有效,因为对于对象a, A.print()必须解析为a类内存块中的vptr,这是a的print函数