簡體   English   中英

為什么通過指針靜態訪問類數據成員返回1?

[英]Why does statically accessing class data members via pointers returns 1?

給出以下代碼:

#include <iostream>

using std::cout;

class A {
    public:
        virtual ~A() {}
        int x,y,z;
};

int main (void)
{
    std::cout<<&A::x;
    std::cout<<&A::y;
    std::cout<<&A::z;
}

輸出是:

111

輸出是什么意思? 為什么是1? 是否有任何理由通過指針訪問類成員(沒有創建對象)?

編輯 - 使用:

printf("%p",&A::x);
printf("%p",&A::y);
printf("%p",&A::z);

打印:4,8和C.

現在我覺得更有意義..(字節)但是,還有什么用呢?

沒有為T = &C::m定義的operator<<(std::ostream&, T) 通常你會收到一個錯誤。

但相反,有一個用於T = bool和從成員指針到bool的隱式轉換。 所以你看到的輸出只是那些指針不為空(被轉換為true )的結果。

試試這個,例如:

#include <iomanip>
#include <iostream>

struct A
{
    int x, y, z;
};

int main()
{
    std::cout << std::boolalpha; // print boolean values as text

    std::cout << &A::x << std::endl;
    std::cout << &A::y << std::endl;
    std::cout << &A::z << std::endl;
}

輸出:

真正
真正
真正


請注意,在代碼printf("%p", &A::X) ,您有未定義的行為。

%p說明符的值必須是void* ,並且不存在從成員指針到void* 相反,你有什么別名(類型雙關語)到void* ,這是未定義的行為。 (想象一下, sizeof(&A::x)是4而sizeof(void*)是64;沒有人說這不是這種情況。)

你只需要接受這樣的想法:並非所有指針都可以被視為整數偏移。 我們甚至可以打印一個指針是實現定義的:它可以打印“apple”為null,“pear”為一個值,“milk”為另一個(如果(啞)實現想要)。 我之前已經觸及過價值觀和表現形式之間的差異

在這種情況下,沒有輸出的價值可言 這沒關系,並非所有值都有有意義的打印輸出。 你能做的最多就是打印出各個位:

#include <climits>
#include <iostream>
#include <type_traits>

template <typename T>
auto print_bits(const T& value)
    -> typename std::enable_if<std::is_standard_layout<T>::value>::type
{
    // it's okay to alias a standard-layout type as a sequence of bytes:
    const auto valueAsBytes = reinterpret_cast<const unsigned char*>(&value);

    for (std::size_t byte = 0; byte < sizeof(T); ++byte)
    {
        // print in reverse order
        const std::size_t byteIndex = sizeof(T) - byte - 1;

        const unsigned char byteValue = valueAsBytes[byteIndex];

        for (std::size_t bit = 0; bit < CHAR_BIT; ++bit)
        {
            // print in reverse order
            const std::size_t bitIndex = CHAR_BIT - bit - 1;

            const bool bitValue = (byteValue & (1U << bitIndex)) != 0;

            std::cout << (bitValue ? 1 : 0);
        }

        std::cout << ' ';
    }

    std::cout << std::endl;
}

(我以相反的順序打印字節和位,因為在我的體系結構中,這會將最低有效位放在右邊。我更喜歡以這種方式查看二進制值。)

這給出了:

struct A
{
    int x, y, z;
};

int main()
{
    // example:
    for (unsigned i = 0; i < 64; ++i)
        print_bits(i);

    std::cout << std::endl;

    // member-pointers:
    print_bits(&A::x);
    print_bits(&A::y);
    print_bits(&A::z);
}

輸出:

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010
[...]
00000000 00000000 00000000 00111101
00000000 00000000 00000000 00111110
00000000 00000000 00000000 00111111

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000100
00000000 00000000 00000000 00001000

您對成員指針的看法無法保證。

&A::x創建指向 A成員指針 在某種程度上,指向成員的指針表示該成員在該類中的“位置”。 這些數字究竟意味着什么取決於具體實施。 我猜想在你的特定實現中,它意味着x在類中的索引1上(虛函數表指針在索引0上)。 編輯實際上,GManNickG的答案表明我對這個假設是錯誤的,它只是將指針打印成隱式轉換為bool成員。

請注意, 指向成員的指針不是傳統意義上的指針。 您不能直接取消引用指向成員的指針。 你總是需要一個對象的指針/引用來跟隨它。 示例(使用您的班級):

int main()
{
  int A::*pm;  // pm is a pointer to member of A of type int
  A a;
  pm = &A::x;
  std::cout << a.*pm; //will output a.x
  pm = &A::y;
  std::cout << a.*pm; //will output a.y
  A *pa = &a;
  std::cout << pa->*pm;  //will output pa->y
}

暫無
暫無

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

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