关于C ++中类型一致性的问题?

时间:2011-07-07 09:18:54

标签: c++ types

我正在阅读一些C ++文本并获得以下代码:

class A { };
class B : public A { };

void main() {
   A* p1 = new B; // B may be larger than A :OK [Line 1]
   B* p2 = new A; // B may be larger than A :Not OK [Line 2]
}

我有两个问题:

  1. 我不明白作者在第1行和第2行中的评论是什么意思
  2. 为什么我们不能在第2行做?

8 个答案:

答案 0 :(得分:8)

嗯,“更大”不是关键所在。真正的问题是“是一种”关系。

class B的任何对象也属于class A类型(由于继承,class B也是class A),所以第一行是可以的(指向{{的指针) 1}}也可以指向class A)的对象,但反之则不正确(class B不是class A,甚至可能不知道class B存在),所以第二行不会编译。

答案 1 :(得分:7)

作者向您展示他不了解C ++(或一般的编程)。没有涉及尺寸(“更大”)的问题。问题是B“isA”A,因此可以使用指向A的指针初始化指向B的指针。但事实恰恰相反。

答案 2 :(得分:1)

评论很愚蠢,真的。对象大小与它没有太大关系。问题是你可以隐式地向上转换指针类型,但不能向下转换。

BTW,main 必须的返回类型为int。不是void

答案 3 :(得分:1)

这里的每个人都给出了正确的答案,但我想指出作者所说的“更大”等等 考虑这两个类:

class Animal {
  public:
   bool bIsHungry;
};

class Bird : public Animal {
  public:
    bool bIsFlying;
}

然后我打电话

Animal* animal = new Bird; // B may be larger than A :OK [Line 1]

程序分配足够的空间以适应变量“bIsHungry”和变量“bIsFlying”。 (但是,除非你将“动物”命名为“动物”,否则你只能访问“bIsHungry”,即使“bIsFlying”也为记忆中的“动物”保留。)

致电时

Bird* parrot = new Animal; // B may be larger than A :Not OK [Line 2]

程序只分配足够的空间来适应变量“bIsHungry”。然而,“parrot”的用户可能想要编写诸如

之类的代码
if(parrot->bIsFlying)
{   //doSomething()
    ...
}

这不起作用,因为使用“new Animal”,程序只为Animal类分配空间,即“bIsHungry”,并且没有为“bIsFlying”分配内存。编译器已“看到”并将“抱怨”,即报告错误。

答案 4 :(得分:0)

因为B来自A,指针B *不能指向A.

答案 5 :(得分:0)

B* p2 = new A;无效,因为指向B的指针可能希望B获得的信息多于A

示例:

class B : public A {
public:
    int notInA;
};

B* p2 = new A;
p2->notInA = 5; // Wait, which notInA are we talking about?
                // p2 is really an A, and As don't have notInA!

答案 6 :(得分:0)

当您使用指针时,指针值是一个内存位置。这意味着您可以将指针设置为指向内存中的任何点。为了“取消引用”该内存并使用该点存储的对象,您需要知道期望的对象类型。
当B类继承A类时,B将包含“A”。 Sharptooth是正确的说是存在“Is-A”关系。 “B”是“A”,但“A”不是“B” 问题在以下代码中完全相同:

string* s = new string("");
int a = 44;
s = (string*)&a; //compiler error if not cast
cout << s; // randomness printed.

答案 7 :(得分:0)

class B : public A { }; 

A* p1 = new B; // B may be larger than A :OK [Line 1]
B* p2 = new A; // B may be larger than A :Not OK [Line 2]
  

我不明白作者在第1行和第2行的评论意思。
  为什么我们不能在2号线做?

class B派生自class A,从它包含的成员变量的角度来看 - 意味着它拥有A所拥有的一切以及它选择添加的任何东西。在你的简单代码中,B没有添加任何内容,但如果它确实有其他数据成员,那么显然需要比更简单的A类型更多的内存。如果它添加了一个虚拟成员函数,其中A没有,则可以期望编译器在B中添加一个指针,该指针记录虚拟调度表的地址,列出其virtual成员函数的地址。如果感觉像编译器也可以自由添加填充。

因此,一般情况是派生类的大小是其基类大小的>=

A* p1 = new B; // B may be larger than A :OK [Line 1]

这里,从堆/免费存储中分配实际需要的空间B,以及p1中存储的内存地址。如果B大于A,则没有任何区别 - 无论如何它都在其他地方 - 关键是保证B*能够存储在{{1}中}}

A*

这里,在堆上创建了一个新的B* p2 = new A; // B may be larger than A :Not OK [Line 2] ,但程序员正试图告诉编译器该地址有一个A。编译器不会相信它(除非被强制) - 你只会得到编译器时间错误。如果您强制编译器(例如p2 =(B *)(新A)B p2 ) to treat the memory address in B as if it were an B , then it may later try to access additional data it expects to be part of any A`:额外数据成员,虚拟调度指针等。