ชั้นในสามารถเข้าถึงตัวแปรส่วนตัวได้หรือไม่?


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";

ข้อผิดพลาดนี้เกิดขึ้นเมื่อฉันคอมไพล์กับคลาส Outer :: Inner 'ไม่มีสมาชิกชื่อ `var'

คำตอบ:


120

ชั้นในคือเพื่อนของชั้นเรียนที่ถูกกำหนดไว้ภายใน
ใช่; วัตถุของการพิมพ์ที่Outer::Innerสามารถเข้าถึงตัวแปรสมาชิกของวัตถุของการพิมพ์varOuter

แตกต่างจาก Java แม้ว่าจะไม่มีความสัมพันธ์ระหว่างอ็อบเจ็กต์ประเภทOuter::Innerและอ็อบเจ็กต์ของคลาสพาเรนต์ คุณต้องสร้างความสัมพันธ์แม่ลูกด้วยตนเอง

#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
ในทางเทคนิคในมาตรฐาน C ++ ปัจจุบันคลาสที่ซ้อนกันไม่มีการเข้าถึงพิเศษสำหรับคลาสที่ปิดล้อม ดูวินาทีที่ 11.8.1 ของมาตรฐาน อย่างไรก็ตามยังเห็นข้อบกพร่องมาตรฐานนี้: open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45
Greg Rogers

1
สำหรับสิ่งที่คุ้มค่า GCC ปฏิบัติตามมติที่เสนอไว้ที่นั่นคอมไพเลอร์อื่น ๆ ก็อาจทำเช่นกัน
Greg Rogers

24
ขณะนี้มาตรฐาน C + 11 เป็นไปตามคำอธิบายข้างต้นแล้ว
Martin York

1
ใน Java คลาสภายในที่ไม่คงที่จะได้รับการอ้างอิงโดยปริยาย (ตัวชี้) ไปยังอินสแตนซ์ของคลาสภายนอกเมื่อเข้าถึงคลาสภายในเป็นครั้งแรก ในการเขียนข้อความนี้ใหม่ jvm กำลังเขียนโค้ดให้คุณโดยปริยายซึ่งคล้ายกับที่ @LokiAstari แสดงให้เราเห็นในคำตอบของเขา นี่คือข้อความที่ตัดตอนมาจากEffective Java 2nd Ed "Item 22: Favor static member class over nonstatic": "หากคุณละเว้นตัวปรับแต่งนี้ (คีย์เวิร์ดแบบคงที่เมื่อประกาศคลาสภายใน) แต่ละอินสแตนซ์จะมีการอ้างอิงที่ไม่เกี่ยวข้องไปยังอินสแตนซ์ที่ล้อมรอบ"
David Lee

3
@ โลกิแอสตาริ: ฉันอ่านประโยคสุดท้าย "คุณต้องสร้างความสัมพันธ์กับแม่ลูกด้วยตนเอง" และตีความส่วนของโค้ดที่ตามมาเป็นตัวอย่างวิธีการทำอย่างถูกต้อง !
Brent Baccala

32

คลาสภายในสามารถเข้าถึงสมาชิกทั้งหมดของคลาสภายนอก แต่ไม่มีการอ้างอิงโดยนัยไปยังอินสแตนซ์คลาสพาเรนต์ (ไม่เหมือนกับความแปลกประหลาดบางอย่างกับ Java) ดังนั้นหากคุณส่งการอ้างอิงไปยังคลาสชั้นนอกไปยังคลาสชั้นในก็สามารถอ้างอิงอะไรก็ได้ในอินสแตนซ์คลาสภายนอก


7
นี่เป็นเรื่องจริงจาก c ++ 11
thrantir

6

สิ่งใดก็ตามที่เป็นส่วนหนึ่งของ Outer ควรเข้าถึงสมาชิกของ Outer ทั้งหมดไม่ว่าจะเป็นภาครัฐหรือเอกชน

แก้ไข: คอมไพเลอร์ของคุณถูกต้อง var ไม่ใช่สมาชิกของ Inner แต่ถ้าคุณมีข้อมูลอ้างอิงหรือตัวชี้ไปที่อินสแตนซ์ของ Outer ก็สามารถเข้าถึงสิ่งนั้นได้


2

var ไม่ใช่สมาชิกของชั้นใน

ในการเข้าถึง var ควรใช้ตัวชี้หรือการอ้างอิงไปยังอินสแตนซ์คลาสภายนอก เช่น pOuter-> var จะใช้งานได้ถ้าชั้นในเป็นเพื่อนของชั้นนอกหรือ var เป็นสาธารณะถ้าเป็นไปตามมาตรฐาน C ++ อย่างเคร่งครัด

คอมไพเลอร์บางตัวถือว่าคลาสชั้นในเป็นเหมือนเพื่อนของชั้นนอก แต่บางคนอาจไม่ทำ ดูเอกสารนี้สำหรับคอมไพเลอร์ IBM :

"คลาสที่ซ้อนกันถูกประกาศภายในขอบเขตของคลาสอื่นชื่อของคลาสที่ซ้อนกันเป็นคลาสที่อยู่ภายในของคลาสที่ปิดล้อมเว้นแต่คุณจะใช้พอยน์เตอร์การอ้างอิงหรือชื่ออ็อบเจ็กต์ที่ชัดเจนการประกาศในคลาสที่ซ้อนกันสามารถใช้ได้เฉพาะโครงสร้างที่มองเห็นได้เท่านั้นซึ่งรวมถึง พิมพ์ชื่อสมาชิกแบบคงที่และตัวนับจากคลาสที่ปิดล้อมและตัวแปรส่วนกลาง

ฟังก์ชันสมาชิกของคลาสที่ซ้อนกันเป็นไปตามกฎการเข้าถึงปกติและไม่มีสิทธิ์การเข้าถึงพิเศษสำหรับสมาชิกของคลาสที่ปิดล้อม ฟังก์ชันสมาชิกของคลาสที่ปิดล้อมไม่มีการเข้าถึงพิเศษสำหรับสมาชิกของคลาสที่ซ้อนกัน "


4
ไม่ถูกต้อง. ดูคำตอบอื่น ๆ - 3 ปีก่อนหน้านี้ "ถ้าปฏิบัติตามมาตรฐาน C ++ อย่างเคร่งครัด" ก็จะได้คำตอบที่แตกต่างจากของคุณ ตั้งแต่ร่างต้นสำหรับ C ++ 11 คลาสที่ซ้อนกันสามารถเข้าถึงสมาชิกทั้งหมดของพาเรนต์ผ่านการอ้างอิง / ตัวชี้ มีความต้องการที่จะประกาศอย่างชัดเจนไม่เป็นหรือfriend publicใครจะสนใจว่า IBM ผิดพลาด / ล้าสมัยในอดีตที่ลิงก์ตาย? คำตอบนี้ล้าสมัยไปแล้วเมื่อ 3 ปีก่อนที่จะโพสต์
underscore_d

1

ก่อนอื่นคุณกำลังพยายามเข้าถึงสมาชิกที่ไม่คงที่varนอกคลาสซึ่งไม่ได้รับอนุญาตใน C ++

คำตอบของมาร์คถูกต้อง

สิ่งใดก็ตามที่เป็นส่วนหนึ่งของ Outer ควรเข้าถึงสมาชิกของ Outer ทั้งหมดไม่ว่าจะเป็นภาครัฐหรือเอกชน

ดังนั้นคุณสามารถทำสองสิ่งได้ทั้งประกาศvarเป็นstaticหรือใช้การอ้างอิงของอินสแตนซ์ของคลาสภายนอกเพื่อเข้าถึง 'var' (เนื่องจากคลาสเพื่อนหรือฟังก์ชันต้องการการอ้างอิงเพื่อเข้าถึงข้อมูลส่วนตัวด้วย)

ตัวแปรคงที่

เปลี่ยนvarเป็นstaticถ้าคุณไม่ต้องการvarเชื่อมโยงกับอินสแตนซ์ของคลาส

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

}

เอาต์พุต - var: 1

ตัวแปรไม่คงที่

การอ้างอิงของออบเจ็กต์ต้องเข้าถึงตัวแปรสมาชิกที่ไม่คงที่

#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);

}

เอาต์พุต - var: 1

แก้ไข - ลิงก์ภายนอกคือลิงก์ไปยังบล็อกของฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.