Set derived class field by converting base class p

2019-07-12 21:00发布

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;
}

It's working for b=100, but I dont know by which rules it works. Where is b stored? I just don't know how its called to google it.

4条回答
女痞
2楼-- · 2019-07-12 21:02

The behaviour is undefined. You can only cast a to B* if it is a pointer to a B.

Don't do this.

You couldn't even write A* a = new B; followed by (dynamic_cast<B*>(a))->foo(); since the classes are not polymorphic types.

查看更多
SAY GOODBYE
3楼-- · 2019-07-12 21:06

Basically, what is happening here is undefined behaviour. It doesn't have a special name; most likely it is called a programming mistake. The memory layout of your class A is:

int a;

The memory layout of B is:

int a;
int b;

So in your case, you only allocate space for a but you are lucky that the space immediately after it is free (so that no other information is overwritten) and that it doesn't border on unallocated space (otherwise, a fault might occur when trying to write to an unallocated page). So b is stored in free space.

In short: don't rely on this code to work!

查看更多
Rolldiameter
4楼-- · 2019-07-12 21:08

Your code will lead to 2 undefined behaviour:

  1. When you cast your instance of A as a B.
  2. When you use the member variable b (this variable does not exist in memory).

Here is pontential implementation to use an instance of B as a pointer of 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();
}
查看更多
贪生不怕死
5楼-- · 2019-07-12 21:13

@anderas has provided a very good explanation why the behavior is undefined.

Here is a relevant clause from the standard (n4431, emphasis mine):

11 ...

If the rvalue of type “pointer to cv1 B” points to a B that is actually a sub-object of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.

[expr.static.cast]

So, the cast in your code is undefined.

The following would work:

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'
}
查看更多
登录 后发表回答