将基类指针转换为派生的类指针

Converting base class pointer to derived class pointer

本文关键字:指针 派生 转换 基类      更新时间:2023-10-16

如下所示,我正在尝试将基类指针转换为派生的类指针。我期望以下代码中的编译器错误,但不会报告任何错误。还有功能" somemethod_2"打印值10。

#include <iostream>
using namespace std;
class Base {
public:
    Base() {
        cout << "Base class constructorn";
    }
};
class Derived : public Base
{
public:
    int Val;
    Derived() {
        cout << "Derived class constructorn";
    }
    void SomeMethod(void)
    {
        cout << "SomeMethodn";
    }
    void SomeMethod_1(void)
    {
        Val = 10;
    }
    void SomeMethod_2(void)
    {
        cout << Val;
    }
};

int main()
{
    Base* BaseObj = new Base();
    Derived* DerivedObj = (Derived*) BaseObj;
    DerivedObj->SomeMethod();    # Expecting compiler error
    DerivedObj->SomeMethod_1();
    DerivedObj->SomeMethod_2();
    return 0;
}

演员,尤其是C风格的演员,告诉编译器闭嘴,了解许多错误和警告,并保证您会自行冒险知道自己在做什么。

使用不指向该类型对象的指针在大多数情况下是未定义的行为。不确定的行为就是这样 - 对可能发生的事情没有任何要求,因此您可能会遇到编译器错误或运行时错误。或者,您可能有"工作"(无论这可能意味着什么(或完全出乎意料的东西。

,就特定情况下实际发生的事情而言,这些功能最有可能使用不属于*BaseObj的相邻内存来存储int,但是此后恰好无关紧要。但是,如果您记得对象delete,那么当时您有可能遇到问题,因为堆为堆内存的内存功能可能已经使用了覆盖的内存。

请注意,如果Base至少具有一个虚拟函数(例如驱动器(,并且如果您使用了更安全的dynamic_cast而不是最小安全的C风格铸件,则铸件的结果将是一个无效的指针,因为dynamic_cast检查对象是否实际是该类型。

class Base {
public:
    Base() {
        cout << "Base class constructorn";
    }
    virtual ~Base() = default;
};
// ...
int main()
{
    Base* BaseObj = new Base();
    Derived* DerivedObj = dynamic_cast<Derived*>(BaseObj);
    if (DerivedObj) {
        DerivedObj->SomeMethod();
        DerivedObj->SomeMethod_1();
        DerivedObj->SomeMethod_2();
    } else {
        std::cout << "Not a Derivedn";
    }
    delete BaseObj; // Don't forget to match every "new" with a "delete".
    return 0;
}
Derived* DerivedObj ....
DerivedObj->SomeMethod();    # Expecting compiler error

我期望编译器错误

没有理由在这里期望编译器错误。DerivedObj是具有成员函数SomeMethodDerived的指针,因此函数调用良好,并且需要编译器来成功编译它。

现在,通过指针DerivedObj和调用成员函数的间接行为是否取决于指针是否有效。在这种情况下,它无效,因此该程序的行为不确定。

也" somemethod_2"功能打印值10。

这是未定义行为的一个例子。

您刚刚执行了基本*的C风格铸件,以衍生*。函数的物种方法是在派生类中定义的,因此,其呼叫是合法的*,而不是编译时间错误。成员函数不是类实例的一部分,而是将其放置在代码段中,并且在隐藏参数的情况下可以为特定实例的成员函数调用。如果您没有数据成员,甚至没有切片。在指针铸造以检查是否施放的内容后,这总是一个好主意,代表有效的指针。当然,在C 中,我们将Dynamic_cast用于此类用例。