İç İç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) {}
};Yuvalanmış Node sınıfı, LinkedList sınıfına sıkı sıkıya bağlıdır; sadece bu bağlamda anlamlıdır. 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 aynı erişim kuralları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 iseYönle ilgili önemli bir ayrıntı: iç içe geçmiş bir sınıf (nested class), kapsayan sınıfın (enclosing class) bir üyesidir ve diğer tüm üyelerle aynı erişim haklarına sahiptir; bu nedenle, herhangi bir friend bildirimi olmadan kapsayan sınıfın özel (private) üyelerine erişebilir. Ancak bunun tersi otomatik değildir; kapsayan sınıf, iç içe geçmiş sınıfın özel (private) üyelerine erişim hakkına sahip değildir.
Bu yüzden yukarıdaki örnekte Node, friend class LinkedList; bildiriminde bulunur: friend bildirimi, kapsayan LinkedList sınıfına Node'un özel (private) üyelerine erişim yetkisi verir; bu, otomatik olmayan tek yöndür.
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 global ad alanını kirletmemek için onu içeriye yerleştireceğiz.
Kodunuzu düzenlemek için iki dosya oluşturacaksınız:
Project.h: İç içe geçmiş birTasksınıfı içeren 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ı almak içingetName()metotlarını ekleyin.Projectsınıfının kendisi bir proje adını (string) ve birTaskişaretçileri koleksiyonunu 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 ismine 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: Girişten bir proje adı ve iki görev adı okuyarak (toplam üç satır) her şeyi bir araya getirin. Verilen adla birProjectoluşturun, her iki görevi de ona ekleyin ve 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ı şu şekilde olmalıdır:Project: <project_name> - <task_name>: [incomplete] - <task_name>: [complete]Her görevin durumuna göre
[complete]veya[incomplete]kullanın.
Bu meydan okuma, 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 tek başına bir anlam ifade etmez. Onu iç içe yerleştirerek, kod yapımızda bu ilişkiyi net bir şekilde belirtmiş oluruz.
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 Proje (Project) oluşturun
// TODO: Her iki görevi de projeye ekleyin
// TODO: Başlangıç durumunu görüntüleyin
// TODO: İlk görevi tamamlayın
// TODO: Değişikliği göstermek için durumu tekrar görüntüleyin
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