簡體   English   中英

通過轉換基類指針來設置派生類字段

[英]Set derived class field by converting base class pointer

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存放在哪里? 我只是不知道它如何調用谷歌它。

基本上,這里發生的是未定義的行為。 它沒有特別的名字; 最有可能的是它被稱為編程錯誤 A類的內存布局是:

int a;

B的內存布局是:

int a;
int b;

因此,在您的情況下,您只為a分配空間,但您很幸運,它后面的空間是空閑的(因此沒有其他信息被覆蓋)並且它沒有在未分配的空間上邊界(否則,可能會發生故障)試圖寫入未分配的頁面)。 所以b存儲在自由空間中。

簡而言之: 不要依賴這個代碼來工作!

@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'
}

行為未定義。 您只能投aB* ,如果它一個指向B

不要這樣做。

你甚至不能寫A* a = new B; 接着是(dynamic_cast<B*>(a))->foo(); 因為類不是多態類型。

您的代碼將導致2個未定義的行為:

  1. 當您將A的實例轉換為B
  2. 當您使用成員變量b (此變量在內存中不存在)。

這是使用B的實例作為A的指針的pontential實現。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM