İç İçe ve Dahili Sınıflar
Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 38 / 104.
Bir iç içe sınıf (nested class), başka bir sınıfın içinde tanımlanan bir sınıftır. Bu teknik, ilgili türleri bir araya getirerek kodu düzenlemeye yardımcı olur ve uygulama ayrıntılarını gizleyerek kapsüllemeyi (encapsulation) artırabilir.
class LinkedList {
public:
class Node { // İç içe geçmiş sınıf
int data;
Node* next;
public:
Node(int d) : data(d), next(nullptr) {}
friend class LinkedList;
};
private:
Node* head;
public:
LinkedList() : head(nullptr) {}
};İç içe geçmiş Node sınıfı, LinkedList sınıfına sıkı bir şekilde bağlıdır - sadece bu bağlamda bir anlam ifade eder. Onu iç içe yerleştirerek bu ilişkiyi belirtiriz ve küresel ad alanını "Node" gibi genel bir isimle kirletmekten kaçınırız.
İç içe sınıflar, öğrendiğiniz erişim kurallarının aynısını takip eder. private bölümünde bildirilen bir iç içe sınıfa yalnızca dış sınıf içinden erişilebilir.
public olarak bildirildiğinde, harici kod onu kapsam operatörü ile kullanabilir:
LinkedList::Node node(42); // Sadece Node public iseÖnemli bir detay: iç içe geçmiş sınıf (nested class), dış sınıfın özel (private) üyelerine otomatik olarak erişim sağlamaz. Bunlar, sadece aynı ad alanını (namespace) paylaşan ayrı sınıflardır.
Eğer iç içe geçmiş sınıfın erişime ihtiyacı varsa, yukarıdaki örnekte gösterildiği gibi onu bir friend olarak bildirmeniz gerekir.
Görev
KolayGörevlerin bir proje içinde organize edildiği basit bir görev yönetim sistemi kuralım. Bu, iç içe geçmiş sınıflar (nested classes) için mükemmel bir senaryodur — bir Task sadece bir Project bağlamında anlamlıdır, bu nedenle kodumuzu düzenli tutmak ve küresel ad alanını (global namespace) kirletmemek için onu içeriye yerleştireceğiz.
Kodunuzu düzenlemek için iki dosya oluşturacaksınız:
Project.h: İçinde iç içe geçmiş birTasksınıfı barındıran birProjectsınıfı tanımlayın.İç içe geçmiş
Tasksınıfınız, dışarıdan erişilebilmesi içinProjectsınıfının public bölümünde bildirilmelidir. Bir görev adını (string) ve bir tamamlanma durumunu (bool) saklamalıdır. Ona adı alan ve görevi varsayılan olarak tamamlanmamış olarak ayarlayan bir yapıcı (constructor) verin. Görevi tamamlandı olarak işaretlemek içincomplete(), durumunu kontrol etmek içinisComplete()ve adını almak içingetName()metotlarını ekleyin.Projectsınıfının kendisi bir proje adını (string) veTaskişaretçilerinden (pointers) oluşan bir koleksiyonu saklamalıdır. Proje adını alan bir yapıcı, yeni bir görev oluşturan ve projeye ekleyen biraddTask(const std::string& taskName)metodu, bir görevi adına göre bulup tamamlayan bircompleteTask(const std::string& taskName)metodu ve proje adını ve ardından her görevin durumunu gösteren birdisplayStatus()metodu sağlayın.Task,Projectiçinde iç içe geçtiği için,Projectsınıfı görevlerle doğrudan çalışabilir. Yıkıcıda (destructor) dinamik olarak ayrılmış görevleri temizlemeyi unutmayın.main.cpp: Girdiden bir proje adı ve iki görev adı (toplam üç satır) okuyarak her şeyi bir araya getirin. Verilen adla birProjectoluşturun, her iki görevi de ona ekleyin, ardından başlangıç durumunu görüntüleyin. İlk görevi tamamlayın ve değişikliği göstermek için durumu tekrar görüntüleyin.displayStatus()için çıktı formatı şöyle olmalıdır:Project: <project_name> - <task_name>: [incomplete] - <task_name>: [complete]Her görevin durumuna göre
[complete]veya[incomplete]kullanın.
Bu zorluk, iç içe geçmiş sınıfların ilgili türleri düzenlemeye nasıl yardımcı olduğunu gösterir — Task sınıfı Project sınıfına sıkı sıkıya bağlıdır ve kendi başına bir anlam ifade etmez. Onu iç içe yerleştirerek, kod yapımızda bu ilişkiyi net bir şekilde belirtmiş oluruz.
Kopya kağıdı
Bir iç içe sınıf (nested class), başka bir sınıfın içinde tanımlanan bir sınıftır. İlgili türleri bir araya getirerek kodun düzenlenmesine yardımcı olur ve kapsüllemeyi (encapsulation) artırır.
class LinkedList {
public:
class Node { // İç içe sınıf
int data;
Node* next;
public:
Node(int d) : data(d), next(nullptr) {}
friend class LinkedList;
};
private:
Node* head;
public:
LinkedList() : head(nullptr) {}
};İç içe sınıflar standart erişim kurallarına tabidir. Private bölümündeki bir iç içe sınıfa yalnızca dış sınıf içinden erişilebilir. Public olarak bildirildiğinde, harici kod kapsam operatörü (scope operator) ile onu kullanabilir:
LinkedList::Node node(42); // Sadece Node public iseİç içe sınıf, dış sınıfın özel (private) üyelerine otomatik olarak erişim hakkına sahip değildir. Erişim gerekiyorsa, onu bir friend olarak bildirin:
friend class LinkedList;Kendin dene
#include <iostream>
#include <string>
#include "Project.h"
using namespace std;
int main() {
// Girdiyi oku
string projectName;
string task1Name;
string task2Name;
getline(cin, projectName);
getline(cin, task1Name);
getline(cin, task2Name);
// TODO: Verilen isimle bir Project oluştur
// TODO: Her iki görevi de projeye ekle
// TODO: Başlangıç durumunu görüntüle
// TODO: İlk görevi tamamla
// TODO: Değişikliği göstermek için durumu tekrar görüntüle
return 0;
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarC++ Build ve DerlemeBaşlık Dosyaları ve Kaynak DosyalarıAd Alanları ve KapsamC++'ta OOP'ye GirişSınıflar ve Nesneler'this' İşaretçisiMetotlar (Üye Fonksiyonlar)Öznitelikler (Veri Üyeleri)Ctor ve Dtor TemelleriÖzet - Basit Hesap Makinesi4Sınıf Özellikleri
Örnek ve Statik ÜyelerGetter ve Setter MetotlarıConst Üye FonksiyonlarMutable Anahtar KelimesiStatik Metotlar ve DeğişkenlerFriend Fonksiyonlar ve SınıflarÖzet - Banka Hesabı Yöneticisi7Kalıtım
Temel KalıtımKalıtım Erişim SeviyeleriCtor ve Dtor Çağrılma SırasıMetot Geçersiz KılmaSanal Fonksiyonlar ve VTableÇoklu KalıtımSanal KalıtımÖzet - Çalışan Hiyerarşisi10STL Genel Bakış
STL Genel Bakış ve FelsefesiSTL KonteynerleriİteratörlerSTL AlgoritmalarıFunctor'lar ve Lambda İfadeleriÖzet - Kelime Frekansı13Tasarım Kalıpları 1. Bölüm
Tasarım Kalıplarına GirişSingleton KalıbıFactory ve Abstract FactoryBuilder KalıbıObserver KalıbıStrategy Kalıbı2Bellek Yönetimi
Stack ve Heap Bellekİşaretçiler ve ReferanslarDinamik Bellek (new/delete)C++'ta Akıllı İşaretçilerC++'ta RAIIÖzet - Dinamik Dizi Yöneticisi5Kapsülleme
C++'da Erişim BelirleyicilerDerinlemesine Erişim BelirleyicilerBilgi GizlemeStruct vs Classİç İçe ve Dahili SınıflarÖzet - Öğrenci Kayıt Sistemi8Çok Biçimlilik
Derleme ve Çalışma Zamanı Çok BiçimliliğiFonksiyon Aşırı YüklemeSanal Fonksiyonlara Yeniden BakışSaf Sanal FonksiyonlarSoyut SınıflarC++'ta Arayüz TasarımıDynamic Casting ve RTTIÖzet - Şekil Hesaplayıcı3Yapıcılar ve Yıkıcılar
Varsayılan YapıcıParametreli YapıcıKopya YapıcıTaşıma YapıcısıYapıcı İlklendirme ListeleriTemsilci YapıcılarYıkıcılara Derinlemesine BakışÜç / Beş / Sıfır KuralıÖzet - String Sınıfı6Operatör Aşırı Yükleme
Operatör Aşırı Yüklemeye GirişAritmetik Operatör Aşırı YüklemeKarşılaştırma Operatörü Aşırı YüklemeStream OperatörleriAtama Operatörü Aşırı Yükleme[] ve () Operatör Aşırı YüklemeTip Dönüşüm OperatörleriÖzet - Matris Sınıfı9Şablonlar
Fonksiyon ŞablonlarıSınıf ŞablonlarıŞablon ÖzelleştirmeVariadic ŞablonlarSFINAE ve Type Traits TemelleriÖzet - Generic Konteyner