0

编辑:代码都不是我的,都是给我的,我只是从对象分配方法的角度分析它。

我在内存分配方面遇到了很大的困难。我向你保证,在过去的 5 个小时里,我已经在这里查看了一百个示例。我知道这可能措辞不当,我提前道歉。

1.) 我不明白为什么第 2 版打印的是 A 类的 f() 而不是 B 类的。线

A* objA1 = objB;

正在声明一个指针 objA1,它指向 A 类型的对象,并将其地址分配给 objB 指向的位置 B(2,3)。我读过这句话“如果它们是堆动态对象,那么你可以将 b1 分配给 a1”。当我调用 objA1->f() 时,我只是说去这个位置,哦,你找到了 B 吗?将其转换为 A 并调用 f()。

2.) 我会认为版本 1 切片 objB,因为它是说设置这个已经为 A 分配空间的对象,等于更大的 B。但是如果我把 cout << objB.bf; 在此分配之后,它仍然有效。是 A objA1 = objB; 不是静态声明 objA1?再一次,为什么不打印 B 的 f()?

3.) 两个 objA1 分配有什么区别?至于什么功能只能与两者之一一起使用。如果你想给它一个过时的分类,你能称之为“堆动态”吗?

class A {
  private:
    int a;
  public:
    A(int ia) {a = ia;}
    void f() { 
      cout << "Call to method f defined in class A" << endl;
    }
};
 class B : public A {
  private:
    int b;
  public:
    B(int ia, int ib) : A(ia) {b = ib;}
    void f() { 
      cout << "Call to method f specialized in class B" << endl; 
    }
    void bf() { 
      cout << "Call to class B own method bf" << endl; 
    }
}; 
// C++ driver - Version 1
void main() { 
  A objA = A(1);
  B objB = B(2,3);

  objA.f();
  objB.f();
  objB.bf(); 

  A objA1 = objB;
  objA1.f();
}

 // C++ driver - Version 2
void main() {
  A* objA = new A(1);
  B* objB = new B(2,3);

  objA->f();
  objB->f();
  objB->bf(); 
  A* objA1 = objB;
  objA1->f();
} 
4

2 回答 2

2

virtual您需要像在基类中一样声明希望以多态方式(通过指向基的指针)调用的函数。当编译器virtual通过指向对象的指针(或引用)遇到对函数的调用时,它会在函数中查找对象的动态类型,而不是静态类型。因此,只需virtual将您的函数定义放在前面A

virtual void f() { 
  cout << "Call to method f defined in class A" << endl;
}

您的行A objA1 = objB;确实对您的对象进行了切片,只是将其中的一部分B复制到. 您将只能调用的成员函数。然而,它仍然是同一个对象——它仍然是 a并且具有所有可用的成员函数。你可以愉快地打电话,但不是nor 。AobjA1AobjA1objBBBobjB->bf()objA->bf()objA1->bf()

如果有疑问,只需查看您正在调用函数的对象的类型。如果是,A你只能调用A' 函数,同样使用B. 如果您通过指针访问并调用virtual函数,则调用属于dynamic type对象的函数(而不是指针所指的类型

于 2012-12-07T17:54:32.623 回答
1

C++ 默认不使用动态调度。这意味着调用p->f()whenp被声明为X *p始终调用X::f(),而不管 指向的实例的动态类型如何p。要启用动态调度,必须声明该函数virtual。这与 Java/C# 形成对比,其中所有成员函数都是隐式的virtual

“版本 1”中的切片确实发生了,但是,objB分配到某处绝不会影响。它objA是受切片影响的(即它忽略了objB不属于 的部分A)。

于 2012-12-07T17:55:49.840 回答