C++ 在动态强制转换行为之后调用特定类方法

C++ 在动态强制转换行为之后调用特定类方法,c++,pointers,casting,C++,Pointers,Casting,这与我发布的另一个问题不同,我有以下代码: class Base { public: Base() { }; virtual void Method() { cout << "Base Method"; } }; class Derived : public Base { public: virtual void Method() { cout << "Override

这与我发布的另一个问题不同,我有以下代码:

class Base
{
public:
    Base()
    {

    };


    virtual void Method()
    {
        cout << "Base Method";
    }
};

class Derived : public Base
{
public:
    virtual void Method()
    {
        cout << "Override Method";
    }
};


class Derived2 : public Derived
{
public:

    Derived2()
    {

        cout << "Derived2 constructor";
    }
    void Method()
    {
        cout << "Override2 Method";
    }
};

int main()
{

    Base *myPointer = new Derived();

    dynamic_cast<Derived2*>(myPointer)->Derived2::Method();

    Sleep(700);

    delete myPointer;

    return 0;
}
如果我写

dynamic_cast<Derived2*>(myPointer)->Method();
有一个失败,dynamic_cast返回NULL,NULL->Method引发异常,这是我所期望的,但是如果我写

dynamic_cast<Derived2*>(myPointer)->Derived2::Method();

该函数在不调用Derived2构造函数的情况下成功。方法甚至不是静态函数,这是怎么回事?

您通过在空指针上调用成员函数触发了未定义的行为。如果使用dynamic_cast,则必须在取消引用之前检查返回的指针是否为NULL,或者100%确保从不将其强制转换为不是要强制转换的对象或其父对象类型的类型。

您通过调用NULL指针上的成员函数触发了未定义的行为。如果使用dynamic_cast,则必须在取消引用之前检查返回的指针是否为NULL,或者100%确保从不将其强制转换为不是要强制转换的对象或其父对象类型的类型。

未定义行为。您的代码违反了严格的别名,即使您的实现出现了错误,并且dynamic_cast在应该返回NULL时没有返回NULL,或者您通过尝试执行此功能将其更改为静态或重新解释强制转换以及其他一些卑鄙的东西。您观察到的输出是不相关的。

未定义的行为。您的代码违反了严格的别名,即使您的实现出现了错误,并且dynamic_cast在应该返回NULL时没有返回NULL,或者您通过尝试执行此功能将其更改为静态或重新解释强制转换以及其他一些卑鄙的东西。当您执行Derived2::Method时,您观察到的输出是不相关的;您正在确切地告诉编译器要调用什么函数。这意味着它将直接调用它。此外,您的成员函数不做任何事情,也不依赖任何成员变量,因此直接调用它很容易,而且不会因为它不访问任何内容而崩溃。但是,在第一个示例中,由于您没有明确告诉它要调用哪个函数,它必须查找该函数,但由于您是在空指针上调用它,因此程序崩溃

然而,在这两种情况下,您都在调用未定义的行为,我上面解释的只是一个实现细节,这可能与其他实现不同;您正在确切地告诉编译器要调用什么函数。这意味着它将直接调用它。此外,您的成员函数不做任何事情,也不依赖任何成员变量,因此直接调用它很容易,而且不会因为它不访问任何内容而崩溃。但是,在第一个示例中,由于您没有明确告诉它要调用哪个函数,它必须查找该函数,但由于您是在空指针上调用它,因此程序崩溃


然而,在任何一种情况下,您都在调用未定义的行为,我上面解释的只是一个实现细节,这可能与其他实现不同。

与您的问题无关,但在指向Base的指针上使用delete实际上指向派生了动态类型的对象是UB,因为Base没有虚拟析构函数。不完全使用new/delete可以避免这种情况:使用派生变量,然后使用指向基点的指针或引用来引用它。不过,让析构函数虚拟并没有什么坏处。未定义的行为。向Derived2添加一个成员,并尝试在Derived2::Method中访问它。与您的问题无关,但在指向Base的指针上使用delete,该指针实际上指向具有派生动态类型的对象是UB,因为Base没有虚拟析构函数。不完全使用new/delete可以避免这种情况:使用派生变量,然后使用指向基点的指针或引用来引用它。不过,让析构函数虚拟并没有什么坏处。未定义的行为。将成员添加到Derived2并尝试在Derived2::Method中访问它。请检查它。Derived2*myPointer=动态\u castmyPointer;如果myPointer==NULL…@David,则任何内容都不会变成NULL指针,如果转换失败,dynamic_cast将返回NULL指针,这是因为myPointer没有指向Derived2Check类型的对象。Derived2*myPointer=动态\u castmyPointer;如果myPointer==NULL…@David,则任何内容都不会变成NULL指针,如果转换失败,dynamic_cast将返回NULL指针,这是因为myPointer不指向Derived2类型的对象。这与严格的别名无关,这是未定义的行为,因为它取消了对空指针的引用。因为在该位置没有Derived2对象,但他将其别名为一个。因此,即使他使用了static_cast,它仍然是UB。这与严格的别名无关,这是未定义的行为,因为它取消了对空指针的引用。因为在该位置没有Derived2对象,但他将其别名为一个。因此,即使他使用静态_cast,它仍然是UB。