Friend Fonksiyonlar ve Sınıflar
Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 32 / 104.
Bazen sınıfınızın dışındaki bir fonksiyonun veya sınıfın, onun özel (private) üyelerine erişmesi gerekir. Bu üyeleri genel (public) yapmak yerine, C++, kapsüllemeyi (encapsulation) korurken seçici erişim sağlamak için friend anahtar kelimesini sunar.
Bir arkadaş fonksiyon (friend function) bir sınıfın içinde bildirilir ancak o sınıfın bir üyesi değildir. Sınıfın private ve protected üyelerine erişebilir:
class Box {
double width;
public:
Box(double w) : width(w) {}
// printWidth'i friend olarak bildir
friend void printWidth(const Box& b);
};
// Friend fonksiyon tanımı - bir üye fonksiyon DEĞİLDİR
void printWidth(const Box& b) {
std::cout << b.width; // Özel üyeye erişebilir
}printWidth'in kapsam çözünürlük operatörü olmadan sınıfın dışında tanımlandığına dikkat edin. Bu, özel erişim ayrıcalıklarına sahip olan normal bir fonksiyondur.
Ayrıca bir sınıfın tamamını arkadaş (friend) yapabilir, böylece tüm üye fonksiyonlarına özel (private) üyelere erişim yetkisi verebilirsiniz:
class Engine {
int horsepower;
friend class Mechanic; // Mechanic özel (private) üyelere erişebilir
public:
Engine(int hp) : horsepower(hp) {}
};
class Mechanic {
public:
void diagnose(const Engine& e) {
std::cout << e.horsepower; // İzin verildi - Mechanic bir arkadaştır (friend)
}
};Arkadaşlık karşılıklı değildir - eğer Engine, Mechanic sınıfını arkadaş olarak bildirirse, Mechanic, Engine'in özel (private) üyelerine erişebilir, ancak bunun tersi geçerli değildir. Arkadaşları (friends) idareli kullanın, çünkü sınıflar arasında sıkı bir bağ (tight coupling) oluştururlar. Bunlar en çok operatör aşırı yüklemesi (operator overloading) ve yakından ilgili yardımcı fonksiyonlar için kullanışlıdır.
Görev
KolayBir MessageReader sınıfının, bir SecureMessage sınıfında saklanan şifreli mesajları okumak için özel erişime ihtiyaç duyduğu güvenli bir mesajlaşma sistemi kuralım. Bu, arkadaş fonksiyonları (friend functions) ve arkadaş sınıfları (friend classes) kullanmak için mükemmel bir senaryodur.
Kodunuzu düzenlemek için iki dosya oluşturacaksınız:
SecureMessage.h: Özel mesaj verilerini saklayan ve güvenilir varlıklara seçici erişim sağlayan birSecureMessagesınıfı tanımlayın. Sınıfınız şunlara sahip olmalıdır:- Özel (private) üyeler:
content(string) vesecretKey(int) - İçeriği ve gizli anahtarı alan bir yapıcı (constructor)
- Özel üyelere erişebilmesi için
MessageReadersınıfını arkadaş (friend) sınıf olarak bildirin - Yalnızca sağlanan anahtar gizli anahtarla eşleşirse içeriği döndüren, aksi takdirde
"Access Denied"döndüren birdecryptMessage(const SecureMessage& msg, int key)arkadaş fonksiyonu bildirin
Ardından aynı başlık dosyasında
MessageReadersınıfını tanımlayın:- Mesajın özel
contentüyesine doğrudan erişen ve onu döndüren birreadContent(const SecureMessage& msg)metodu - Sağlanan anahtarın mesajın
secretKeyüyesiyle eşleşip eşleşmediğini kontrol eden ve"Valid"veya"Invalid"döndüren birverifyKey(const SecureMessage& msg, int key)metodu
Son olarak, sınıflardan sonra
decryptMessagearkadaş fonksiyonunu tanımlayın.- Özel (private) üyeler:
main.cpp: Hem arkadaş fonksiyonların hem de arkadaş sınıfların işleyişini gösterin. Girişten bir mesaj içeriği, bir gizli anahtar ve bir test anahtarı okuyun (her biri ayrı bir satırda), ardından:- İçerik ve gizli anahtar ile bir
SecureMessagenesnesi oluşturun - Bir
MessageReadernesnesi oluşturun - Okuyucunun
readContent()metodunu kullanarak"Reader access: <content>"yazdırın - Test anahtarı ile
verifyKey()metodunu kullanarak"Key verification: <result>"yazdırın - Test anahtarı ile arkadaş fonksiyonunu kullanarak
"Decrypt with test key: <result>"yazdırın - Orijinal gizli anahtar ile arkadaş fonksiyonunu kullanarak
"Decrypt with correct key: <result>"yazdırın
- İçerik ve gizli anahtar ile bir
Arkadaş fonksiyonların, kapsam çözünürlük operatörü (scope resolution operator) olmadan sınıf dışında tanımlandığını unutmayın — bunlar özel erişim ayrıcalıklarına sahip normal fonksiyonlardır. MessageReader sınıfı, bir arkadaş olduğu için tüm metodlarında SecureMessage'ın özel üyelerine doğrudan erişebilir.
Anahtar girişlerini std::stoi() kullanarak dizelerden tam sayılara dönüştürün. Başlık dosyanızı main.cpp içine #include "SecureMessage.h" kullanarak dahil edin.
Kopya kağıdı
friend anahtar kelimesi, kapsüllemeyi (encapsulation) korurken özel (private) üyelere seçici erişim sağlar.
Arkadaş Fonksiyon (Friend Function): Bir sınıfın içinde bildirilen, ancak sınıfın bir üyesi olmayan, sınıfın özel ve korumalı (protected) üyelerine erişebilen bir fonksiyondur:
class Box {
double width;
public:
Box(double w) : width(w) {}
// Declare friend function
friend void printWidth(const Box& b);
};
// Define outside class without scope resolution operator
void printWidth(const Box& b) {
std::cout << b.width; // Can access private member
}Arkadaş Sınıf (Friend Class): Bir sınıfın tamamı arkadaş olarak bildirilebilir, bu da o sınıfın tüm üye fonksiyonlarına özel üyelere erişim yetkisi verir:
class Engine {
int horsepower;
friend class Mechanic; // All Mechanic methods can access private members
public:
Engine(int hp) : horsepower(hp) {}
};
class Mechanic {
public:
void diagnose(const Engine& e) {
std::cout << e.horsepower; // Allowed
}
};Önemli Noktalar:
- Arkadaşlık karşılıklı değildir - eğer A sınıfı B'yi arkadaş olarak bildirirse, B sınıfı A'nın özel üyelerine erişebilir, ancak tersi geçerli değildir.
- Arkadaş fonksiyonlar, kapsam çözme operatörü (scope resolution operator) olmadan sınıfın dışında tanımlanır.
- Sınıflar arasında sıkı bir bağ (tight coupling) oluşturdukları için arkadaşları idareli kullanın.
- En çok operatör aşırı yüklemesi (operator overloading) ve yakından ilgili yardımcı fonksiyonlar için kullanışlıdır.
Kendin dene
#include <iostream>
#include <string>
#include "SecureMessage.h"
using namespace std;
int main() {
// Girdiyi oku
string messageContent;
string secretKeyStr;
string testKeyStr;
getline(cin, messageContent);
getline(cin, secretKeyStr);
getline(cin, testKeyStr);
int secretKey = stoi(secretKeyStr);
int testKey = stoi(testKeyStr);
// TODO: İçerik ve gizli anahtar ile bir SecureMessage oluşturun
// TODO: Bir MessageReader nesnesi oluşturun
// TODO: readContent() kullanarak "Reader access: <content>" yazdırın
// TODO: Test anahtarı ile verifyKey() kullanarak "Key verification: <result>" yazdırın
// TODO: Test anahtarı ile decryptMessage kullanarak "Decrypt with test key: <result>" yazdırın
// TODO: Doğru anahtar ile decryptMessage kullanarak "Decrypt with correct key: <result>" yazdı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ı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