簡體   English   中英

這是關於成員訪問規則的正確摘要嗎?

[英]Is this a correct summary on member access rules?

我試圖完全理解在 C++ 標准的[class.access]部分的多個段落中定義的成員訪問規則。 它們非常復雜甚至令人困惑,因此我需要一個簡短但准確和詳盡的總結

我編譯了這個程序來測試在幾種情況下受保護成員的可訪問性(因為受保護成員的規則是最復雜的): 1

#include <iostream>

class B {
  protected:
    int i = 1;
    static int const I = 1;
};

class X: public B {
  protected:
    int j = 2;
    static int const J = 2;
  public:
    void f();
    friend void g();
};

class D: public X {
  protected:
    int k = 3;
    static int const K = 3;
};

void X::f() {
  B b;
  X x;
  D d;
  //std::cout << b.i;  // error: 'i' is a protected member of 'B'
  std::cout << b.I;
  std::cout << x.i;
  std::cout << x.I;
  std::cout << x.j;
  std::cout << x.J;
  std::cout << d.i;
  std::cout << d.I;
  std::cout << d.j;
  std::cout << d.J;
  //std::cout << d.k;  // error: 'k' is a protected member of 'D'
  //std::cout << d.K;  // error: 'K' is a protected member of 'D'
}

void g() {
  B b;
  X x;
  D d;
  //std::cout << b.i;  // error: 'i' is a protected member of 'B'
  //std::cout << b.I;  // error: 'I' is a protected member of 'B'
  std::cout << x.i;
  std::cout << x.I;
  std::cout << x.j;
  std::cout << x.J;
  std::cout << d.i;
  std::cout << d.I;
  std::cout << d.j;
  std::cout << d.J;
  //std::cout << d.k;  // error: 'k' is a protected member of 'D'
  //std::cout << d.K;  // error: 'K' is a protected member of 'D'
}

int main() {
  B b;
  X x;
  D d;
  //std::cout << b.i;  // error: 'i' is a protected member of 'B'
  //std::cout << b.I;  // error: 'I' is a protected member of 'B'
  //std::cout << x.i;  // error: 'i' is a protected member of 'B'
  //std::cout << x.I;  // error: 'I' is a protected member of 'B'
  //std::cout << x.j;  // error: 'j' is a protected member of 'X'
  //std::cout << x.J;  // error: 'J' is a protected member of 'X'
  //std::cout << d.i;  // error: 'i' is a protected member of 'B'
  //std::cout << d.I;  // error: 'I' is a protected member of 'B'
  //std::cout << d.j;  // error: 'j' is a protected member of 'X'
  //std::cout << d.J;  // error: 'J' is a protected member of 'X'
  //std::cout << d.k;  // error: 'k' is a protected member of 'D'
  //std::cout << d.K;  // error: 'K' is a protected member of 'D'
  return 0;
}

我對直接可訪問性得出了這個結論: 2

我的總結正確嗎?


1我在 C++ 17 中使用了 Clang 9.0.0 編譯器。

2對類B的成員i的訪問可以是直接的,即通過該類: bi直接訪問),也可以是間接的,即通過該類的派生類Ddi繼承訪問)。 由於派生類繼承的成員是該派生類的成員,其可訪問性發生了變化(參見[class.access/base-1] ),對類成員的繼承訪問可以被視為對繼承成員的直接訪問該類的派生類。 換句話說,只需要考慮直接訪問

3我在這里的條款與標准[class.access/base-5.4]的引用條款略有不同:

當在類 N 中命名時,成員 m 可在點 R 訪問,如果

  • 存在一個 N 的基類 B 可以在 R 處訪問,並且當在類 B 中命名時,可以在 R 處訪問 m。

這是因為編譯器的行為不同,我的感覺是編譯器是正確的。 在我看來,該標准的條款存在兩個問題:

  • 訪問點 R 應該僅限於 B 類的成員和朋友(這是編譯器通過為程序中的main中的d.*訪問引發錯誤來執行的操作);
  • 類 N 中的成員 m 應該被限制為從類 B 繼承,而不是被類 N 覆蓋(這是編譯器會通過為X::fdidIdjdJ訪問引發錯誤而做的事情) g ,是否在程序中的D中覆蓋了iIjJ )。

如果您的問題是基於訪問權限,那么這些是 C++ 中的規則。 我將在下面做一個基本的總結,但要獲得詳盡的解釋,請到這里 這將更詳細地介紹每個方法的工作原理。

民眾
類的公共成員可以在任何地方訪問

受保護
1. 致該班的成員和朋友
2. 對該類的任何派生類的成員和朋友(直到 C++17),但僅當訪問受保護成員的對象的類是該派生類或該派生類的派生類時

私人的
一個類的私有成員只能被該類的成員和朋友訪問,無論成員是在相同還是不同的實例上

要查看示例,請轉到上面的鏈接。

對於嵌套類,您在基類的范圍內,因此可以訪問私有成員和受保護成員。 如果成員是靜態的,您將能夠直接訪問,否則必須構造該類的對象才能訪問該類中的那些成員。 這是上面class X一個例子:

class X: public B {
public:
    class A {
    public:
        void b() {
            std::cout << J << std::endl;
            std::cout << S << std::endl;
        }
        void d(X x) {
            std::cout << x.j << std::endl;
            std::cout << x.s << std::endl;
        }
    };

    void f();

protected:
    int j = 2;
    static int const J = 2;
private:
    friend void g();
    int s = 3;
    static int const S = 4;
};

以下是將 public、protected 和 private 用於繼承時的含義

民眾
當類使用公共成員訪問說明符從基類派生時,基類的所有公共成員都可以作為派生類的公共成員訪問,基類的所有受保護成員都可以作為派生類的受保護成員(私有成員)訪問除非加為好友,否則永遠無法訪問基地的

受保護
當類使用受保護成員訪問說明符從基類派生時,基類的所有公共成員和受保護成員都可以作為派生類的受保護成員訪問(基類的私有成員永遠不能訪問,除非是友元的)
私人的
當一個類使用私有成員訪問說明符從基類派生時,基類的所有公共成員和受保護成員都可以作為派生類的私有成員訪問(基類的私有成員永遠不能訪問,除非是友元的)。

注意:派生類繼承基類的所有方法,但有以下例外。

  • 基類的構造函數、析構函數和復制構造函數

  • 重載運算符(例如基類)——它們可能不會像您期望的那樣運行,並且應該以您為每個類的每個運算符覆蓋的方式實現。

  • 基類的友元函數。

現在至於朋友說明符,這是來自 cpp 參考here這里您將有示例和詳細說明如何使用它。

當涉及到標准庫時,您還將在那里找到大量信息的示例,您還可以看到將來標准中的內容以及您的編譯器支持的功能。

你弄錯了一個不太直觀的訪問,c++ 依賴於編譯,其中一個效果是內存中的所有實例都是“相同的”,並且如果該類上的函數可以接受“他自己”的引用,則可以訪問彼此的私有變量,有關更多詳細信息,請檢查類變量this

#include <iostream>

class MyClass{

    int num = 69;

    public:

        void set_num(int n){
            num = n;
        };
        int get_num() {
            return num;
        }

        int get_num_from(MyClass * ptr_ref) {
            return ptr_ref->num;
        }
        int get_num_from(MyClass ref) {
            return ref.num;
        }

};


int main(){

    MyClass class_a;
    MyClass class_b;

    class_a.set_num(0);

    std::cout << "class_a -> " << class_a.get_num() << std::endl;
    std::cout << "class_b ref -> " << class_b.get_num_from(class_a) << std::endl;
    std::cout << "class_b ptr_ref -> " << class_b.get_num_from(&class_a) << std::endl;

}

輸出:

class_a -> 0
class_b ref -> 0
class_b ptr_ref -> 0

暫無
暫無

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

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