Các lớp bên trong có thể truy cập các biến private không?


117
class Outer {

    class Inner {
    public:
        Inner() {}
        void func() ;
    };

private:
    static const char* const MYCONST;
    int var;
};

void Outer::Inner::func() {
    var = 1;
}

const char* const Outer::MYCONST = "myconst";

Lỗi này xảy ra khi tôi biên dịch với lớp Outer :: Inner 'không có thành viên nào có tên là `var'

Câu trả lời:


120

Lớp bên trong là bạn của lớp mà nó được định nghĩa bên trong.
Vì vậy, có; một đối tượng của kiểu Outer::Innercó thể truy cập biến thành viên varcủa một đối tượng kiểu Outer.

Không giống như Java, không có sự tương quan giữa một đối tượng của kiểu Outer::Innervà một đối tượng của lớp cha. Bạn phải tạo mối quan hệ cha mẹ con theo cách thủ công.

#include <string>
#include <iostream>

class Outer
{
    class Inner
    {
        public:
            Inner(Outer& x): parent(x) {}
            void func()
            {
                std::string a = "myconst1";
                std::cout << parent.var << std::endl;

                if (a == MYCONST)
                {   std::cout << "string same" << std::endl;
                }
                else
                {   std::cout << "string not same" << std::endl;
                }
            }
        private:
            Outer&  parent;
    };

    public:
        Outer()
            :i(*this)
            ,var(4)
        {}
        Outer(Outer& other)
            :i(other)
            ,var(22)
        {}
        void func()
        {
            i.func();
        }
    private:
        static const char* const MYCONST;
        Inner i;
        int var;
};

const char* const Outer::MYCONST = "myconst";

int main()
{

    Outer           o1;
    Outer           o2(o1);
    o1.func();
    o2.func();
}

14
Về mặt kỹ thuật trong tiêu chuẩn C ++ hiện tại, một lớp lồng nhau KHÔNG có quyền truy cập đặc biệt vào lớp bao quanh của nó. Xem phần 11.8.1 của tiêu chuẩn. TUY NHIÊN xem thêm lỗi tiêu chuẩn này: open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45
Greg Rogers

1
Đối với giá trị của nó, GCC tuân theo giải pháp đề xuất được đưa ra ở đó, các trình biên dịch khác có thể cũng làm như vậy.
Greg Rogers

24
Tiêu chuẩn C + 11 hiện phù hợp với mô tả ở trên.
Martin York

1
Trong Java, lớp bên trong không tĩnh được mặc nhiên cung cấp một tham chiếu (con trỏ) đến thể hiện của lớp bên ngoài khi lớp bên trong được truy cập lần đầu. Để diễn đạt lại điều này, jvm đang ngầm viết cho bạn một mã tương tự như những gì @LokiAstari đã cho chúng ta thấy trong câu trả lời của anh ấy. Đây là một đoạn trích từ Hiệu quả Java 2nd Ed "Mục 22: Ủng hộ các lớp thành viên tĩnh hơn là không có nội dung": "Nếu bạn bỏ qua công cụ sửa đổi này (từ khóa static khi khai báo lớp bên trong), mỗi phiên bản sẽ có một tham chiếu không liên quan đến phiên bản bao quanh của nó".
David Lee,

3
@Loki Astari: Tôi đọc câu cuối cùng "Bạn phải tạo mối quan hệ cha mẹ con theo cách thủ công" và diễn giải đoạn mã sau đó làm ví dụ về cách thực hiện điều đó một cách chính xác !
Brent Baccala

32

Một lớp bên trong có quyền truy cập vào tất cả các thành viên của lớp bên ngoài, nhưng nó không có tham chiếu ngầm đến một cá thể lớp cha (không giống như một số điều kỳ lạ với Java). Vì vậy, nếu bạn chuyển một tham chiếu đến lớp bên ngoài cho lớp bên trong, nó có thể tham chiếu bất cứ thứ gì trong cá thể lớp bên ngoài.


7
điều này là đúng từ c ++ 11
thrantir

6

Bất cứ thứ gì là một phần của Outer đều phải có quyền truy cập vào tất cả các thành viên của Outer, công khai hay riêng tư.

Chỉnh sửa: trình biên dịch của bạn đúng, var không phải là thành viên của Inner. Nhưng nếu bạn có một tham chiếu hoặc con trỏ đến một phiên bản của Outer, nó có thể truy cập vào đó.


2

var không phải là thành viên của lớp bên trong.

Để truy cập var, nên sử dụng một con trỏ hoặc tham chiếu đến một cá thể lớp ngoài. ví dụ: pOuter-> var sẽ hoạt động nếu lớp bên trong là bạn của bên ngoài, hoặc, var là công khai, nếu một lớp tuân theo tiêu chuẩn C ++ nghiêm ngặt.

Một số trình biên dịch coi các lớp bên trong là bạn của lớp bên ngoài, nhưng một số có thể không. Xem tài liệu này cho trình biên dịch IBM :

"Một lớp lồng nhau được khai báo trong phạm vi của một lớp khác. Tên của lớp lồng nhau là cục bộ cho lớp bao quanh nó. Trừ khi bạn sử dụng con trỏ, tham chiếu hoặc tên đối tượng rõ ràng, các khai báo trong lớp lồng nhau chỉ có thể sử dụng các cấu trúc hiển thị, bao gồm nhập tên, thành viên tĩnh và liệt kê từ lớp bao quanh và các biến toàn cục.

Các hàm thành viên của một lớp lồng nhau tuân theo các quy tắc truy cập thông thường và không có đặc quyền truy cập đặc biệt đối với các thành viên của các lớp bao quanh chúng. Các hàm thành viên của lớp bao quanh không có quyền truy cập đặc biệt vào các thành viên của lớp lồng nhau. "


4
Sai lầm. Xem các câu trả lời khác - 3 năm trước đó. "nếu một người tuân theo tiêu chuẩn C ++ nghiêm ngặt", họ sẽ đạt được các câu trả lời khác với câu trả lời của bạn. Theo bản nháp ban đầu cho C ++ 11, các lớp lồng nhau có thể truy cập tất cả các thành viên của cha thông qua một tham chiếu / con trỏ. Không có yêu cầu khai báo rõ ràng friendhoặc public. Ai quan tâm nếu trong quá khứ IBM đã sai lầm / lỗi thời, tại một liên kết chết? Câu trả lời này đã lỗi thời 3 năm trước khi nó được đăng.
underscore_d

1

Trước hết, bạn đang cố gắng truy cập thành viên không tĩnh varbên ngoài lớp không được phép trong C ++.

Câu trả lời của Mark là đúng.

Bất cứ thứ gì là một phần của Outer đều phải có quyền truy cập vào tất cả các thành viên của Outer, công khai hay riêng tư.

Vì vậy, bạn có thể làm hai điều, hoặc khai báo vardưới dạng statichoặc sử dụng tham chiếu của một thể hiện của lớp bên ngoài để truy cập 'var' (vì một lớp hoặc hàm bạn bè cũng cần tham chiếu để truy cập dữ liệu riêng tư).

Var tĩnh

Thay đổi varthành staticNếu bạn không muốn varđược liên kết với các thể hiện của lớp.

#include <iostream>

class Outer {

private:
    static const char* const MYCONST;
    static int var;

public:
   class Inner {
    public:
        Inner() {
          Outer::var = 1;
        }
        void func() ;
    };
};

int Outer::var = 0;

void Outer::Inner::func() {
    std::cout << "var: "<< Outer::var;
}

int main() {
  Outer outer;
  Outer::Inner inner;
  inner.func();

}

Đầu ra- var: 1

Var không tĩnh

Tham chiếu của một đối tượng là phải truy cập bất kỳ biến thành viên không tĩnh nào.

#include <iostream>

class Outer {

private:
    static const char* const MYCONST;
    int var;

public:
   class Inner {
    public:
        Inner(Outer &outer) {
          outer.var = 1;
        }
        void func(const Outer &outer) ;
    };
};

void Outer::Inner::func(const Outer &outer) {
    std::cout << "var: "<< outer.var;
}

int main() {
  Outer outer;
  Outer::Inner inner(outer);
  inner.func(outer);

}

Đầu ra- var: 1

Chỉnh sửa - Liên kết bên ngoài là liên kết đến Blog của tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.