基类型未转换为派生类型但可以调用其函数和变量

埃姆雷·埃尔多

据我所知,创建的类型不能OOP转换为派生类型但我遇到过这样的事情,我没想到会工作。以下是示例类:

class Base {
public: 
    virtual void Call1() { std::cout << "Base call 1" << std::endl; }
    virtual void Call2() { std::cout << "Base call 2" << std::endl; }
};

class Derived : public Base{
public:
    void Call1() { std::cout << "Derived call 1" << std::endl; }
    void Call2() { std::cout << "Derived call 2" << std::endl; }

    void SetAll() { x = 15; y = 16; z = 16; } // Just random numbers
    
    int GetX() { return x; }
    int GetY() { return y; }       
    int GetZ() { return z; }
private:
    int x;
    int y;
    int z;
};

在主程序中:

Base* b1 = new Base;
Derived* d1 = (Derived*)(b1); // This shouldn't be okay as far as i know

// How is this part working?
d1->SetAll();
std::cout << d1->GetX() << std::endl;
std::cout << d1->GetY() << std::endl;
std::cout << d1->GetZ() << std::endl;

这是输出:

15
16
16

即使派生类型的大小更大,出于某种原因,我可以调用它的函数并操作它的派生类型的变量,即使我没有为其分配足够的内存,因为Base对象的大小较小。那么这段代码是如何工作的呢?

凯文·安德森

这里发生的事情大部分都被评论所覆盖,但有一点我还没有看到:SetAll()方法是如何设置内存的,以及在哪里设置。作为记录,我在下面描述的是可能发生的事情,因为您在这里非常喜欢“未定义的行为”。

Derived* d1 = (Derived*)(b1); // This shouldn't be okay as far as i know

正如你所说,这不应该也不行d1 认为它指向一个Derived类,但实际上不是。但是,一切都将表现得好像它是。正如其他人所说,您基本上已经reinterpret_cast对指针进行了操作。

d1->SetAll();

这里发生的是SetAll()方法将设置存储位置的其中x,y和z如果D1被指向一个实际的例子Derived所以你覆盖了你没有分配的内存,但它通常仍然存在。因此,如果b1是 0x00004000(或其他),则d1->x是 0x0004004,或 4 个字节(或 8 个,或编译器依赖于它如何放置基类和派生类)超出类的“开始” Base如果d1实际上指向 aDerived就可以了,但它指向 aBase这意味着它不指向它“拥有”的内存区域。因此未定义的行为。

std::cout << d1->GetX() << std::endl;
std::cout << d1->GetY() << std::endl;
std::cout << d1->GetZ() << std::endl;

好了d1 没有写入到它现在正在寻找的区域xy以及z从现在开始,所以它发现了它们。问题是它写在它应该写的地方之外。

简短回答:dynamic_cast在基类和子类之间进行转换时,如果可以,请使用nullptr如果不允许,它将返回

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

自动从派生类转换为基类成员变量的类型

C# 可以让基类中的泛型函数知道调用派生类的类型吗?

从基类的特定派生类型调用特定函数

我们可以在不知道其真实类型的情况下将基类指针转换为派生类指针吗?

用户定义的转换是否将派生类类型转换为基类类型?

调用派生类型的模板化函数

基类实现INotifyPropertyChanged:派生类型可以使用其PropertyChanged事件吗?

在Golang中将基本类型转换为派生类型

来自派生类的调用函数,该派生类存储在具有基类类型的Map中

动态将派生类类型转换为基类C#

C#-从派生类调用基类方法时的类型转换问题

自动转换为派生类型而不检查派生类型?

从具有通用返回类型的crtp基类的派生类中调用函数

是否可以自动转换为大多数派生类型?

重载函数,以便它可以将基类转换为派生类作为参数

基类方法可以返回派生类的类型吗?

通过打字稿中的派生类型调用构造函数

为什么派生类指针指向基类可以调用派生类成员函数?

Autofac和自变量:解析为更多派生类型

在基类和派生类上进行操作时,如何返回派生类型?

从基类和派生类之外的方法返回任何派生类类型

对派生类中的成员变量使用派生类型

为什么初始化派生类变量并分配给其基类类型不允许访问其成员?

从基类方法返回派生类型

无法将派生类型隐式转换为基本泛型类型

从Go中的派生类型调用方法

通过派生类型调用的静态方法

MyPy类型提示使用命名参数定义的函数,但可以使用** kwargs吗?

派生类的构造函数可以比其基类的构造函数具有更多的参数吗?