键入指针"横向"在C ++中

时间:2016-06-19 14:18:11

标签: c++ polymorphism

我对C ++没有经验,但试图学习。

以下示例包含与"相关的":

的类层次结构
  • 儿童 Parent1 Parent2
  • 的孩子
  • Parent2 VirtualGrandParent 的孩子。
  • Parent2 包含一个成员姐妹* m_sister ,它是指向另一个用户定义的对象类型的指针。这是在Parent2的构造函数中初始化并分配了关键字 new 的内存。在执行的某个时刻,该指针设置为0。

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:

#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:

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:

#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:

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

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

VirtualGrandParent.h:

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

问题1 :所以我的主要问题是&#34; sideways&#34;从VirtualGrandParent转换为Parent1?为什么m_sister为0?内存被覆盖了吗? 为什么在m_sister为0之前需要两个方法调用?

问题2 :如果将地址带到WorkerClass.h中的指针ptr,然后将其转换为Parent1*指针,会发生什么情况(下面的示例) )?使用此更改执行代码会导致m_sister未设置为0.我认为这只是一个巧合? (我猜指针指针确实应该是Parent1**类型的?)

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

1 个答案:

答案 0 :(得分:2)

因此,如果我们将父母身份视为树:

VirtualGrandParent
       \
      Parent2        Parent1
            \       /
              Child

然后我们可以看到Parent1和VirtualGrandParent在不同的分支上。因此,当您将VirtualGrandParent* ptr投射到Parent1时,您没有正确地在层次结构中向上或向下投射。相反,它会跨越它而最终在不相关的类之间进行投射 - 这就是它产生无效结果的原因。

要沿着继承层次结构进行转换,请尝试始终至少使用static_cast(或dynamic_cast,如果需要)。使用static_cast,编译器将验证转换是否至少是可能的,否则会出错。在您的情况下,它应该显示错误。

正确演员阵容为static_cast<Parent1*>(static_cast<Child*>(ptr))

至于你关于&ptr的第二个问题......将指针指针作为指向类的指针只是无意义的。如果它看起来有用,那就是未定义行为的不幸运气。 (它可能实际上并没有正常工作,而是解释一些任意的内存,就好像它是你的类一样,然后碰巧有一个非零值,其中somePtr会以任何方式无效。)