以下代码
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”?为什么以及如何发生? 什么指针真的意味着什么?不只是一个地址和内存块的长度?
答案 0 :(得分:3)
将“a”等于“b”?
是
为什么以及如何发生这种情况?
要执行两个指针的比较,编译器将执行到公共类型的转换。在这种情况下,由于A
是B
的基础,转换为A*
,产生的代码相当于:
A* __tmp = b;
if ( a == __tmp ) ...
指针究竟意味着什么?不只是一个地址和内存块的长度?
指针是保存对象地址的变量(没有存储在指针中的大小信息)。但是指针有一个类型,编译器将解释指针所指的内存位置是该类型的对象。存储在指针之外的额外信息允许编译器执行转换。
答案 1 :(得分:0)
a
变量将指向已分配的A
对象的b
类部分。指针只是一个内存地址,仅此而已。重要的是指针指向内存中的数据类型。
答案 2 :(得分:0)
让我们分三个部分分开答案
指针是一个保存另一个变量的内存地址的变量。指向变量的类型很重要,将由编译器检查。可以通过使用指针来强制指针机制(在C ++中应该避免,除非你真的知道你在做什么)。
可以使用指向其父类型(代码中为b
)的指针来引用派生类(代码中的A
)的对象(即变量)。这将允许您访问B
中存在的A成员。正如Richard J. Ross所说,使用指向基类的指针将产生与使用派生类指针相同的地址(除非涉及多重继承)。
虚方法允许您使用基类指针调用派生对象的重载方法。这对于析构函数尤其有用,因为即使使用基类指针(假设析构函数写得很好),也可以放心对象将被正确销毁。
仍然,您的代码在概念上是错误的。因为A
的析构函数不是虚拟的,所以B
b
部分的析构函数不会被调用,因此可能存在内存泄漏和类似问题。
答案 3 :(得分:0)
正如大卫已经提到的,对两个指针a == b
的简单比较会给你True,因为编译器会将它们都转换为公共类型。
但是,如果您要将其修改为(void*)a == (void*)b
,则结果可能为false。
这是因为类A和B具有不同的存储器布局,因为B具有虚拟功能表而A - 不是。
MSVC编译器将虚函数指针放在类的“顶部”,在第一个数据成员之前,但没有什么能阻止其他编译器将它放在“底部”。
您也可以尝试将A类析构函数设为虚拟。
答案 4 :(得分:0)
我在内部c ++对象模型中找到了一些解释,这就像多重继承一样,vptr位于对象的开头。 当基类没有虚拟子类和子类时,指针的赋值将由编译器逐步调整为vptr,
答案 5 :(得分:-1)
该示例是两个指针之间的比较。当他们指向相同的位置时,a将等于b。