C ++期末考试学习资料

时间:2013-06-09 19:59:45

标签: c++

我一直在研究这个问题,为即将到来的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来自超级类B中调用A的构造函数,我理解指针*pa指向{{ 1}}让它访问&b的基类方法,但它如何在foo而不是B::print()中打印值?

4 个答案:

答案 0 :(得分:2)

这是因为你在B中覆盖了print()。因为在类A中没有将foo()定义为虚拟,所以调用了类A中的foo()。

答案 1 :(得分:1)

由于B来自A,因此每个B A。因此pa可以指向类型为A的对象或任何派生类型。但是对象的类型不会改变,因此b仍然是B类型并且表现如此。唯一的限制是,由于它是由A指针引用的,因此只能引用在基类A中声明的方法和成员变量。

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

答案 2 :(得分:1)

virtual void print()

函数前面的 virtual 这个词使得多态性发挥了作用。当派生类实现一个在基类中声明为virtual的函数时,它将被调用而不是派生类实例的基类函数。

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

答案 3 :(得分:0)

之间的区别
pa->foo();

pa->print();

是由一个简单的事实造成的:

  

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

,来自书籍 Inside C ++对象模型

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

// 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()必须在一个块中解析为 vptr A类的记忆是A的打印功能