1
#include <iostream>
class A
{
public:
    A()
    {
        std::cout << "\n A_Constructor \t" << this <<std::endl;
    }
    void A_Method()
    {
        std::cout <<"\n A_Method \t" << this <<std::endl;
    }
};
class B:public A
{
public:
    B()
    {
        std::cout <<"\n B_Constructor \n";
    }
    void B_Method()
    {
        std::cout <<"\n B_Method \t" << this <<std::endl;
    }
};

int main()
{
    A *a_obj = new A;
    B *b_obj = static_cast<B*> (a_obj);  // This isn't safe.
    b_obj->B_Method();      
    getchar();
    return 0;
}

输出 :

A_Constructor 001C4890
B_Method 001C4890

由于类型转换不涉及运行时检查,static_cast因此不安全。但在这个例子中,我得到了我没想到的东西。由于没有调用 to B::B(),因此它的任何成员都不应该被调用b_obj。尽管如此,我还是得到了输出。

在这个简单的例子中,虽然已知不安全,但我可能已经成功了。我的疑问是——

  • 虽然没有调用B::B(),但我是如何访问class B成员函数的。
  • 有人可以提供一个例子,这是不安全的并且可能会出错(尽管我之前给出的可能是一个坏例子,但更好)。

我是在 Visual Studio 2010 上完成的,并设置了\Wall选项。

4

3 回答 3

4

这是未定义的行为。有时 UB 会导致崩溃。有时它似乎“工作”。你是对的,你不应该这样做,即使在这种情况下发生的坏事较少。

于 2011-01-10T17:52:54.850 回答
0

您正在尝试的是未定义的行为,因此任何事情都可能发生。这似乎工作(并且可能工作)很好,因为您不尝试访问任何数据成员(您没有任何数据成员)。尝试向两个类中添加一些数据成员并从方法中访问它,您将看到行为将变为完全不可预测的。

于 2011-01-10T17:57:44.510 回答
0

我怀疑这个特殊情况是UB。首先,它只是将指针从一种类型转换为另一种类型。由于不涉及虚拟/多重继承,因此不进行指针调整,因此指针值基本保持不变。当然它指向一个错误类型的对象,但是谁在乎呢,只要我们不访问任何 B 成员,即使有一些?即使涉及到指针调整,如果我们不访问它指向的任何内存,仍然可以,但我们没有。

然后,该示例调用 B 的一个方法。由于它不是虚拟的,它只是一个带有隐藏参数的普通函数调用this(想想B::B_Method(this))。现在,this指向一个错误类型的对象,但同样,谁在乎呢?它唯一做的就是打印它,这总是一件安全的事情。

事实上,您甚至可以使用 NULL 指针调用方法。只要该方法不是虚拟的并且不尝试访问this. 我曾经有一个被许多程序使用的库。这个库有一个必须显式构造的类单例类,但实际上没有一个程序这样做。实例指针默认初始化为 NULL,因为它是全局的。由于该类根本没有数据成员,因此它工作得很好。然后我添加了一些,所有程序突然开始崩溃。当我找到原因时,我笑得很开心。我一直在使用一个甚至不存在的对象。

于 2011-01-10T18:45:18.640 回答