Kompozisyon ve Kalıtım Karşılaştırması
Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 76 / 104.
Sınıflar arasındaki ilişkileri tasarlarken iki ana seçeneğiniz vardır: kalıtım ("is-a") ve kompozisyon ("has-a"). Doğru yaklaşımı seçmek, kodunuzun esnekliğini ve sürdürülebilirliğini önemli ölçüde etkiler.
Kalıtım, sınıflar arasında sıkı bir bağ oluşturur. Vehicle sınıfından kalıtım alan bir Car, bu ilişkiye kalıcı olarak bağlıdır:
class Vehicle {
public:
virtual void start() { std::cout << "Starting vehicle\n"; }
};
class Car : public Vehicle {
public:
void start() override { std::cout << "Starting car\n"; }
};Kompozisyon, nesneleri üye olarak dahil ederek daha esnek bir ilişki oluşturur. Bir Car, bir motor olmak yerine bir Engine'e sahiptir:
class Engine {
public:
void start() { std::cout << "Engine running\n"; }
};
class Car {
private:
Engine engine; // Araba bir Motora SAHİPTİR
public:
void start() { engine.start(); }
};Kompozisyonun temel avantajı esnekliktir. Katı bir sınıf hiyerarşisinin kısıtlamaları olmadan bileşenleri kolayca değiştirebilir, çalışma zamanında davranışı değiştirebilir veya birden fazla yeteneği birleştirebilirsiniz. Modern C++ tasarımı, çoğu durumda kalıtım yerine kompozisyonu tercih eder.
Gerçek bir "is-a" ilişkisi olduğunda ve polimorfizme ihtiyaç duyduğunuzda kalıtımı kullanın. İşlevselliği yeniden kullanmak istediğinizde veya ilişki "has-a" veya "uses-a" olarak daha iyi tanımlandığında kompozisyonu kullanın.
Görev
KolayKompozisyonun (composition) kalıtıma (inheritance) karşı ne zaman kullanılacağını gösteren bir bilgisayar sistemi simülatörü oluşturalım. Bir bileşen olmak yerine bileşenlere sahip olan (kompozisyon) bir bilgisayarı modelleyeceksiniz ve kompozisyonun çalışma zamanında parçaları değiştirme esnekliğini nasıl sağladığını göreceksiniz.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
Components.h: Bir bilgisayarın içerebileceği bireysel bileşenleri tanımlayın.Özel (private)
std::string modelveint coresalanlarına sahip birCPUsınıfı oluşturun. Her iki değeri de alan bir yapıcı (constructor),CPU [model] processing with [cores] coresyazdıran birprocess()metodu ve birgetModel()metodu sağlayın.Özel bir
int sizeGBalanına sahip birMemorysınıfı oluşturun. Bir yapıcı,Loading data into [sizeGB]GB RAMyazdıran birload()metodu ve birgetSize()metodu sağlayın.Özel
std::string type("SSD" veya "HDD" gibi) veint capacityGBalanlarına sahip birStoragesınıfı oluşturun. Bir yapıcı,Reading from [capacityGB]GB [type]yazdıran birread()metodu ve her iki alan için de getter metodları sağlayın.Computer.h: Bileşenleri birleştirmek için kompozisyon kullanan birComputersınıfı tanımlayın.Computersınıfınız özel üye nesnelere sahip olmalıdır: birCPU, birMemoryve birStorage. Bu bileşenleri parametrelerden başlatmak için yapıcı başlatma listesini (constructor initialization list) kullanın.Şu metodları uygulayın:
boot()—Booting computer...yazdırır, ardından her biri ayrı satırlarda olmak üzere bellekteload(), depolamadaread()ve CPU'daprocess()metodlarını çağırır.specs()— bilgisayarın özelliklerini şu formatta yazdırır:Computer Specs: - CPU: [model] ([cores] cores) - RAM: [size]GB - Storage: [capacity]GB [type]
main.cpp: Altı girişi okuyun (her biri ayrı bir satırda):- CPU model adı (string)
- CPU çekirdek sayısı (integer)
- GB cinsinden bellek boyutu (integer)
- Depolama türü (string, örneğin "SSD")
- GB cinsinden depolama kapasitesi (integer)
- Bir komut: "boot" veya "specs"
Bileşen nesnelerini oluşturun, ardından kompozisyon kullanarak bir
Computeroluşturun. Komuta bağlı olarakboot()veyaspecs()metodunu çağırın.
Örneğin, Intel i7, 8, 16, SSD, 512 ve boot girişleri ile:
Booting computer...
Loading data into 16GB RAM
Reading from 512GB SSD
CPU Intel i7 processing with 8 coresAMD Ryzen, 6, 32, HDD, 1000 ve specs girişleri ile:
Computer Specs:
- CPU: AMD Ryzen (6 cores)
- RAM: 32GB
- Storage: 1000GB HDDComputer sınıfının herhangi bir bileşenden kalıtım almadığına, aksine onları içerdiğine dikkat edin. Bu "sahip olma" (has-a) ilişkisi, farklı bileşen kombinasyonlarına sahip bilgisayarları kolayca oluşturabileceğiniz veya daha sonra setter metodları eklerseniz bileşenleri değiştirebileceğiniz anlamına gelir. Bu esneklik, kompozisyonun kalıtıma göre temel avantajıdır.
Kopya kağıdı
Sınıflar arasındaki ilişkileri tasarlarken, kalıtım ("is-a" - bir ...'dır) ve kompozisyon ("has-a" - bir ...'ya sahiptir) arasında seçim yapın.
Kalıtım, sınıflar arasında sıkı bir bağ (tight coupling) oluşturur:
class Vehicle {
public:
virtual void start() { std::cout << "Starting vehicle\n"; }
};
class Car : public Vehicle {
public:
void start() override { std::cout << "Starting car\n"; }
};Kompozisyon, nesneleri üye olarak dahil ederek esnek ilişkiler oluşturur:
class Engine {
public:
void start() { std::cout << "Engine running\n"; }
};
class Car {
private:
Engine engine; // Car HAS an Engine
public:
void start() { engine.start(); }
};Hangisi ne zaman kullanılmalı:
- Polimorfizme ihtiyaç duyduğunuz gerçek "is-a" ilişkileri için kalıtım kullanın
- İşlevselliği yeniden kullanmak veya "has-a"/"uses-a" ilişkileri için kompozisyon kullanın
- Modern C++ tasarımı, esnekliği nedeniyle kompozisyonu tercih eder; bileşenleri değiştirebilir, çalışma zamanında davranışı değiştirebilir ve katı hiyerarşiler olmadan yetenekleri birleştirebilirsiniz
Kendin dene
#include <iostream>
#include <string>
#include "Computer.h"
using namespace std;
int main() {
// Girdileri oku
string cpuModel;
getline(cin, cpuModel); // CPU model adı (boşluk içerebilir)
int cpuCores;
cin >> cpuCores; // CPU çekirdek sayısı
int memorySize;
cin >> memorySize; // GB cinsinden bellek boyutu
string storageType;
cin >> storageType; // Depolama türü (örneğin, "SSD")
int storageCapacity;
cin >> storageCapacity; // GB cinsinden depolama kapasitesi
string command;
cin >> command; // Komut: "boot" veya "specs"
// TODO: Bileşen nesnelerini oluşturun (CPU, Memory, Storage)
// TODO: Kompozisyon (composition) kullanarak bir Computer nesnesi oluşturun
// TODO: Komuta bağlı olarak boot() veya specs() fonksiyonunu çağırın
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ı11İleri Düzey OOP Kavramları
Kompozisyon ve Kalıtım KarşılaştırmasıCRTP ile Mixin YapılarıPimpl İdiyomuTür Silme (Type Erasure)Enum Sınıfları ve Güçlü TiplendirmeOOP'de İstisna YönetimiÖzel İstisna Hiyerarşileri3Yapı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