簡體   English   中英

C ++-從班級外部更改私人成員

[英]C++ - Change private member from outside the class

此代碼是否會導致未定義的行為? 還是我會遇到這個問題? (復制沒有函數的完整類,僅復制帶有public修飾符的變量,並修改私有成員拋出該指針)示例:

#include <iostream>

using namespace std;

class Point {

private:

    int x;
    int y;

public:

    Point(int x, int y) {
        this->x = x;
        this->y = y;
    }

    void Print() {
        cout << "(" << x << ", " << y << ")" << endl;
    }

};

struct PointHack {

    int x;
    int y;

};

int main() {
    Point a(4, 5);
    a.Print();
    ((PointHack *) (&a))->x = 1;
    ((PointHack *) (&a))->y = 2;
    a.Print();

    return 0;
}

輸出:

(4, 5)
(1, 2)

(當然有原始的會員訂單)

盡管您的類與布局兼容(請參見下文),但是由於C ++嚴格的別名規則 1禁止此類指針強制轉換,因此代碼仍表現出未定義的行為。

但是:用union替換強制類型轉換使代碼符合標准; 實際上保證可以在C ++ 11中使用:

#include <iostream>

using namespace std;

class Point {

private:

    int x;
    int y;

public:

    Point(int x, int y) {
        this->x = x;
        this->y = y;
    }

    void Print() {
        cout << "(" << x << ", " << y << ")" << endl;
    }

};

struct PointHack {
    int x;
    int y;
};

union pu
{
    Point p;
    PointHack ph;
    pu(int x, int y) : p(x, y) {}
};

int main() {
    pu u(4,5);
    u.p.Print();
    u.ph.x=1;
    u.ph.y=2;
    u.p.Print();
    return 0;
}

這是因為PointPointHack是標准布局類2 (C ++ 11,§9¶7),並共享“公共初始子序列”(§9.2,¶20)。 這樣,如果它們都存儲在同一個聯合體(在此為pu )中,則可以“檢查其中任何一個的公共初始部分” 3

不過,這個答案主要是一種風格的練習。 除非您真的被迫使用,否則不要利用這些技巧。 C ++在必要時提供了更好的方法來訪問私有成員,而又不會殘酷地破壞封裝-您具有吸氣劑/設置器,受保護的繼承,朋友類……而且通常,如果您以目標類不希望的方式訪問私有類成員,您可能違反了該類關於如何修改其數據的假設,這可能導致其方法代碼的行為不穩定。


筆記:

  1. 在C ++中,不能有兩個不相關類型的指針指向同一對象。 此限制主要用於幫助優化器進行有關別名的假設。
  2. 請注意,此要求非常嚴格。 通常,大多數基本上不是C結構的類都不符合此條件。 即使具有不同的訪問限定符也可以打破魔術。
  3. 這個想法是,分配給ph使其成為的“活動對象” union ,然后p.Print()是“檢查”所述“不活動”對象中的一個。

是的,發布的代碼會調用未定義的行為。 不要那樣做

如果您想以某種瘋狂的方式實現某些人完成這個不愉快的目標的方法,請執行以下操作: 使用模板技巧訪問私有成員

但實際上,不要那樣做。

PS:切勿在C ++中使用C樣式的強制轉換。 根據需要使用static_cast,dynamic_cast,reinterpret_cast和const_cast。 C樣式的強制轉換不必要地是不安全的。

我發現了問題

/*code:*/
#include <stdio.h>

void check(short *h,long *k)
{
    *h=5;
    *k=6;
    if (*h == 5)
        printf("strict aliasing problem\n");
}

int main(void)
{
    long      k[1];
    check((short *)k,k);
    return 0;
}
/*
$ gcc -Wall -ansi -pedantic -O0 -o o0 asd.c
$ ./o0
/output: nothing/
$ gcc -Wall -ansi -pedantic -O2 -o o2 asd.c
$ ./o2
/output: strict aliasing problem/
*/

(與c ++中相同)

暫無
暫無

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

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