Bisakah kelas dalam mengakses variabel privat?

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

Kesalahan ini keluar ketika saya mengkompilasi dengan kelas Outer :: Inner 'tidak memiliki anggota bernama `var'

kal
sumber

Jawaban:

120

Kelas dalam adalah teman dari kelas yang didefinisikan di dalamnya.
Jadi iya; sebuah objek bertipe Outer::Innerdapat mengakses variabel anggota varsebuah objek bertipe Outer.

Tidak seperti Java, tidak ada korelasi antara objek bertipe Outer::Innerdan objek kelas induk. Anda harus membuat hubungan orang tua anak secara manual.

#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();
}
Martin York
sumber
14
Secara teknis dalam standar C ++ saat ini, kelas bertingkat TIDAK memiliki akses khusus ke kelas yang melingkupinya. Lihat bagian 11.8.1 dari standar. NAMUN lihat juga cacat standar ini: open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45
Greg Rogers
1
Untuk apa nilainya, GCC mengikuti resolusi yang diusulkan yang diberikan di sana, kompiler lain mungkin juga melakukannya.
Greg Rogers
24
Standar C + 11 sekarang sesuai dengan uraian di atas.
Martin York
1
Di Java, kelas dalam non-statis secara implisit diberi referensi (penunjuk) ke instance kelas luarnya saat kelas dalam pertama kali diakses. Untuk mengubah ini, jvm secara implisit menulis kode untuk Anda yang mirip dengan apa yang @LokiAstari tunjukkan kepada kami dalam jawabannya. Berikut kutipan dari Effective Java 2nd Ed "Item 22: Lebih memilih kelas anggota statis daripada nonstatis": "Jika Anda menghilangkan pengubah ini (kata kunci statis saat mendeklarasikan kelas dalam), setiap instance akan memiliki referensi yang tidak relevan ke instance yang melingkupinya".
David Lee
3
@Loki Astari: Saya membaca kalimat terakhir "Anda harus membuat hubungan orang tua anak secara manual" dan menafsirkan potongan kode yang diikuti sebagai contoh bagaimana melakukannya dengan benar !
Brent Baccala
32

Kelas dalam memiliki akses ke semua anggota kelas luar, tetapi tidak memiliki referensi implisit ke instance kelas induk (tidak seperti beberapa keanehan dengan Java). Jadi, jika Anda meneruskan referensi ke kelas luar ke kelas dalam, itu bisa merujuk apa pun di instance kelas luar.

MSN
sumber
7
ini benar dari c ++ 11
thrantir
6

Apa pun yang merupakan bagian dari Luar harus memiliki akses ke semua anggota Luar, publik atau pribadi.

Edit: kompiler Anda benar, var bukan anggota Inner. Tetapi jika Anda memiliki referensi atau penunjuk ke sebuah instance dari Luar, itu dapat mengaksesnya.

Mark Ransom
sumber
2

var bukan anggota kelas dalam.

Untuk mengakses var, pointer atau referensi ke instance kelas luar harus digunakan. misalnya pOuter-> var akan berfungsi jika kelas dalam adalah teman dari luar, atau, var bersifat publik, jika seseorang mengikuti standar C ++ dengan ketat.

Beberapa kompiler memperlakukan kelas dalam sebagai teman luar, tetapi beberapa mungkin tidak. Lihat dokumen ini untuk kompiler IBM :

"Kelas bertingkat dideklarasikan dalam lingkup kelas lain. Nama kelas bertingkat bersifat lokal untuk kelas yang melingkupinya. Kecuali Anda menggunakan penunjuk eksplisit, referensi, atau nama objek, deklarasi dalam kelas bertingkat hanya dapat menggunakan konstruksi yang terlihat, termasuk ketik nama, anggota statis, dan enumerator dari kelas penutup dan variabel global.

Fungsi anggota kelas bersarang mengikuti aturan akses biasa dan tidak memiliki hak akses khusus untuk anggota kelas yang melingkupinya. Fungsi anggota dari kelas yang melingkupi tidak memiliki akses khusus ke anggota kelas bertingkat. "

xiaochuanQ
sumber
4
Salah. Lihat jawaban lain - 3 tahun sebelumnya. "jika seseorang mengikuti standar C ++ dengan ketat", jawaban mereka berbeda dari Anda. Sejak draf awal untuk C ++ 11, kelas bertingkat dapat mengakses semua anggota induk melalui referensi / pointer. Tidak ada persyaratan untuk menyatakan friendatau public. Siapa yang peduli jika IBM salah / ketinggalan zaman, di masa lalu, di link mati? Jawaban ini sudah ketinggalan zaman 3 tahun sebelum diposting.
underscore_d
1

Pertama-tama, Anda mencoba mengakses anggota non-statis di varluar kelas yang tidak diizinkan di C ++.

Jawaban Mark benar.

Apa pun yang merupakan bagian dari Luar harus memiliki akses ke semua anggota Luar, publik atau pribadi.

Jadi Anda bisa melakukan dua hal, baik mendeklarasikan varsebagai staticatau menggunakan referensi dari sebuah instance dari kelas luar untuk mengakses 'var' (karena kelas atau fungsi teman juga membutuhkan referensi untuk mengakses data pribadi).

Var statis

Ubah varke staticJika Anda tidak ingin vardikaitkan dengan instance kelas.

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

}

Output- var: 1

Variabel non-statis

Referensi objek adalah harus mengakses variabel anggota non-statis.

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

}

Output- var: 1

Edit - Tautan luar adalah tautan ke Blog saya.

Adarsh ​​Kumar
sumber