1

对于以下代码

class A 
{
public:
    ~A()
    {
        std::cout << "a"  << std::endl;
    }
};

class B : public A {
public:
    virtual ~B()
    {
        std::cout << "b"  << std::endl;
    }
};

int main()
{
    B* b = new B();
    A* a = b;

    if (a == b)
    {

    }

    delete a;
}

问题是,“a”是否等于“b”?这是为什么以及如何发生的?指针的真正含义是什么?不仅仅是地址和内存块的长度?

4

6 回答 6

3

“a”会等于“b”吗?

是的

这是为什么以及如何发生的?

为了执行两个指针的比较,编译器将执行到通用类型的转换。在这种情况下,作为A的基数B,转换为A*,产生的代码等效于:

A* __tmp = b;
if ( a == __tmp ) ...

指针的真正含义是什么?不仅仅是地址和内存块的长度?

指针是保存对象地址的变量(指针中不存储大小信息)。但是指针有一个类型,编译器会将指针所指的内存位置解释为该类型的对象。存储在指针外部的额外信息允许编译器执行转换。

于 2012-09-26T01:23:30.377 回答
0

我在 c++ 对象模型内部找到了一些解释,这就像多重继承一样,vptr 位于对象的开头。当基类没有虚拟而子类有虚拟时,指针的分配将由编译器通过 vptr 逐步调整,

于 2012-09-26T06:18:44.827 回答
0

正如大卫已经提到的,两个指针的简单比较a == b会给你 True 因为编译器会将它们都转换为公共类型。但是,如果您将其修改为(void*)a == (void*)b,结果可能是错误的。这是因为 A 类和 B 类有不同的内存布局,因为 B 有一个虚函数表,而 A 没有。

MSVC 编译器将虚函数指针放在类的“顶部”,在第一个数据成员之前,但没有什么能阻止其他编译器将它放在“底部”。

您也可以尝试将 A 类析构函数设为虚拟。

于 2012-09-26T05:03:18.283 回答
0

让我们把答案分成三个部分

指针

指针是一个变量,它保存另一个变量的内存地址。指向变量的类型很重要,编译器会检查它。可以通过使用指向 void 的指针来强制指针机制(在 C++ 中应避免使用,除非您真的知道自己在做什么)。

使用基类指针访问派生类对象

派生类的对象,即变量(b在您的代码中)可以使用指向其父类型的指针(在您的代码中)来引用A。这将允许您访问 A 中存在的成员B。正如 Richard J. Ross 已经说过的,使用指向基类的指针将产生与使用派生类指针相同的地址(除非涉及多重继承)。

虚函数

虚拟方法允许您使用基类指针调用派生对象的重载方法。这对析构函数特别有用,因为即使使用基类指针(假设析构函数写得很好),我们也可以放心,对象将被正确销毁。

不过,您的代码在概念上是错误的。由于 的析构函数A不是虚拟的,所以不会调用B部分的析构函数,因此可能会出现内存泄漏等问题。b

于 2012-09-26T02:12:22.550 回答
0

a变量将指向分配对象的A类部分。b指针只是一个内存地址,仅此而已。重要的是指针指向内存中的数据类型。

于 2012-09-26T01:17:26.323 回答
-1

该示例是两个指针之间的比较。因为它们指向同一个位置,所以 a 将等于 b。

于 2012-09-26T01:30:33.433 回答