简体   繁体   English

在C ++中“横向”类型转换指针时会发生什么

[英]What happens when type-casting a pointer “sideways” in C++

I'm not that experienced with C++, but trying to learn. 我没有C ++的经验,但尝试学习。

The following example consists of a hierarchy of classes which are "related": 以下示例由“相关”的类的层次结构组成:

  • Child is a child of both Parent1 and Parent2 孩子Parent1Parent2的孩子
  • Parent2 is a child of VirtualGrandParent . Parent2VirtualGrandParent的子
  • Parent2 contains a member Sister* m_sister which is a pointer to another user-defined object type. Parent2包含一个成员Sister * m_sister ,该成员是另一个用户定义的对象类型的指针。 This is initialized and allocated memory with keyword new in Parent2's constructor. 使用Parent2的构造函数中的关键字new初始化并分配内存。 At some point in the execution this pointer is set to 0. 在执行过程中的某个时刻,此指针设置为0。

MainClass.cpp: MainClass.cpp:

#include "WorkerClass.h"
using namespace std;

int main() 
{ 
  WorkerClass worker;

  worker.initialize();
  worker.setProperty1();
  worker.setProperty2();
// At this point m_sister (in Parent2) is set to 0x0, which makes the next method call fail (Segmentation fault). What happens?

  worker.setAuntValue();

  return 0;
}

WorkerClass.h: WorkerClass.h:

#include <map>
#include "Child.h"

class WorkerClass
{
public:
    void initialize()
    {
        Child* child1 = new Child();
        m_myMap[0] = child1;
    }

    void setProperty1()
    {
        VirtualGrandParent* ptr = m_myMap[0];
        ((Parent1*) ptr)->setProperty1(6.0);
    }

    void setProperty2()
    {
        VirtualGrandParent* ptr = m_myMap[0];
        ((Parent1*) ptr)->setProperty2(7.0);
    }

    void setAuntValue()
    {
        VirtualGrandParent* ptr = m_myMap[0];
        ((Child*) ptr)->setSisterValue(170.0);
    }

private:
    map<int, VirtualGrandParent*> m_myMap;
};

Child.h 儿童

#include "Parent1.h"
#include "Parent2.h"

class Child : public Parent1, public Parent2
{
public:
    Child(): Parent1(), Parent2() {}
    ~Child(){};
};

Parent1.h: Parent1.h:

class Parent1
{
public:

    Parent1(): m_value1(0.0), m_value2(0.0) {}
    virtual ~Parent1() {};

    void setProperty1(double val) {m_value1=val;}
    void setProperty2(double val) {m_value2=val;}

private:
    double m_value1;
    double m_value2;
};

Parent2.h: Parent2.h:

#include "Sister.h"
#include "VirtualGrandParent.h"

class Parent2 : public VirtualGrandParent
{
public:
    Parent2(): VirtualGrandParent() {m_sister = new Sister();}
    ~Parent2(){};

    void setSisterValue(double val){m_sister->setValue(val);}

protected:
    Sister* m_sister;
};

Sister.h: Sister.h:

class Sister {
public:
    Sister(): m_sisterVal(0.0) {};

    void setValue(double val)
    {
        m_sisterVal=val;
    }
private:
    double m_sisterVal;
};

VirtualGrandParent.h: VirtualGrandParent.h:

class VirtualGrandParent
{
public:
    VirtualGrandParent() {}
    virtual ~VirtualGrandParent(){};
};

Question 1 : So my main question is what happens during the "sideways" casting from VirtualGrandParent to Parent1? 问题1 :所以我的主要问题是从VirtualGrandParent到Parent1的“横向”转换期间会发生什么? Why is m_sister 0? 为什么m_sister为0? Is memory overwritten? 内存被覆盖吗? Why does it take two method calls before m_sister is 0? 为什么在m_sister为0之前需要两个方法调用?

Question 2 : What happens if taking the address to the pointer ptr in WorkerClass.h, and then cast it to a Parent1* pointer (example below)? 问题2 :如果将地址指向WorkerClass.h中指针ptr,然后将其Parent1*转换为Parent1*指针(下面的示例),会发生什么? Executing the code with this change results in m_sister not being set to 0. I assume this is just a coincidence? 执行此更改的代码会导致m_sister未被设置为0。我认为这只是一个巧合? (I guess a pointer-to-pointer really should be of type Parent1** ?) (我想指针到指针的类型应该确实是Parent1** ?)

void setProperty1()
{
    VirtualGrandParent* ptr = m_myMap[0];
    ((Parent1*) &ptr)->setProperty1(6.0);
}

So if we view the parentage as a tree: 因此,如果我们将亲子关系视为一棵树:

VirtualGrandParent
       \
      Parent2        Parent1
            \       /
              Child

Then we can see that Parent1 and VirtualGrandParent are on different branches. 然后我们可以看到Parent1和VirtualGrandParent在不同的分支上。 So when you cast VirtualGrandParent* ptr to Parent1 you aren't properly casting up or down the hierarchy. 因此,当您将VirtualGrandParent* ptrParent1您将无法正确地转换层次结构。 Instead that's casting across it which ends up casting between unrelated classes - and that's why it yields invalid results. 取而代之的是在整个类之间进行转换,最终在不相关的类之间进行转换-这就是为什么它会产生无效结果的原因。

For casting along an inheritance hierarchy, try to always use at least static_cast (or dynamic_cast if desired). 为了沿继承层次结构进行投射,请尝试至少始终使用static_cast (或根据需要使用dynamic_cast )。 With a static_cast the compiler will validate that the cast is at least possible and otherwise give an error. 使用static_cast ,编译器将验证是否至少可以进行static_cast转换,否则将产生错误。 In your case it should show an error. 在您的情况下,它应该显示一个错误。

The proper cast would be static_cast<Parent1*>(static_cast<Child*>(ptr)) 正确的转换应为static_cast<Parent1*>(static_cast<Child*>(ptr))

As for your second question about &ptr ... casting a pointer-to-a-pointer as a pointer-to-a-class is simply nonsense. 至于关于&ptr第二个问题,将指针指向的指针转换为类指针完全是胡说八道。 If it appears work at all, that's the unfortunate luck of undefined behavior. 如果看起来确实可行,那就是不幸的未定义行为。 (And it's probably not actually working correctly, but instead interpreting some arbitrary memory as if it was your class, which then happens to have a non-zero value where somePtr would be but isn't valid in any way.) (它实际上可能无法正常工作,而是将某些任意内存解释为好像是您的类,然后该内存恰好具有一个非零值,其中somePtr将是但无论如何都无效。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM