通过转换基类指针来设置派生类字段

时间:2015-10-12 09:07:42

标签: c++ language-lawyer

class A
{
public: 
    int a;
};
class B:public A
{
public:
    int b;
    void foo()
    {
        b=a*a;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{ 
    A * a=new A;
    a->a=10;
    ((B*)a)->foo();
    cout<<((B*)a)->b;
}

它适用于b=100,但我不知道它的工作原理。 b存放在哪里?我只是不知道它是如何调用谷歌的。

4 个答案:

答案 0 :(得分:6)

基本上,这里发生的是未定义的行为。它没有特别的名字;很可能它被称为编程错误。班级A的内存布局为:

int a;

B的内存布局是:

int a;
int b;

因此,在您的情况下,您只为a分配空间,但幸运的是,它后面的空间是空闲的(因此没有其他信息被覆盖)并且它没有在未分配的空间上边界(否则,尝试写入未分配的页面时可能会发生错误。所以b存储在自由空间中。

简而言之:不依赖此代码工作!

答案 1 :(得分:2)

@anderas提供了一个很好的解释为什么行为未定义。

以下是该标准的相关条款(n4431,强调我的):

  

11 ......

     

如果类型“指向cv1 B的指针”的rvalue指向实际上是D类型对象的子对象的B,则生成的指针指向类型D的封闭对象。否则,演员表的结果未定义

     

[expr.static.cast]

因此,代码中的强制转换是未定义的。

以下方法可行:

class A
{
public: 
    int a;
    virtual void foo() = 0; // make it polymorphic
};
class B:public A
{
public:
    int b;
    virtual void foo()
    {
        b=a*a;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{ 
    A * a=new B;  // create an instance of B
    a->a=10;
    ((B*)a)->foo();
    cout<<((B*)a)->b;

    // don't forget to delete 'a'
}

答案 2 :(得分:1)

行为未定义。如果指向a的指针,则只能将B*投射到B

不要这样做。

你甚至不能写A* a = new B;后跟(dynamic_cast<B*>(a))->foo();,因为这些类不是多态类型。

答案 3 :(得分:0)

您的代码将导致2个未定义的行为:

  1. 当您将A的实例投射为B
  2. 使用成员变量b时(此变量不存在 在记忆中)。
  3. 这是使用B的实例作为A的指针的实际实现。

    class A
    {
    public:
        void setA(int aToSet)
        {
           a = aToSet;
        }
        virtual void foo() = 0;
        virtual void getResult() const = 0;
    private:
        int a;
    };
    
    class B : public A
    {
    public:
        void foo() override
        {
            b = a * a;
        }
        void getResult() const override
        {
            return b;
        }
    private:
        int b;
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    { 
        A *a = new B();
        a->setA(10);
        a->foo();
        cout << a->getResult();
    }