C++ Programlama
- Bir değişkeni başlatmanın (initialization) üç yolu vardır:
- Copy initialization (örneğin
int a = 5;) - Direct initialization (örneğin
int b(5);) - List initialization (örneğin
int c{5};)
- Copy initialization (örneğin
Not
En güvenilir olanı list initialization’dır; çünkü daraltıcı (narrowing) dönüşümlere örneğin bir float değeri doğrudan int’e izin vermez.
-
Tanımlanıp hiç kullanılmayan değişkenler için derleyici uyarı verir. Bu uyarıyı bastırmak için C++17’den itibaren
[[maybe_unused]]özniteliğini kullanabiliriz. -
::operatörü, önünde bir isim (örneğin bir namespace veya sınıf adı) yoksa “global” ad alanını ifade eder.
#include <iostream> // Standart giriş-çıkış kütüphanesi
using namespace std; // Tüm std isimlerini doğrudan kullanmamıza izin verir
// Sadece belli bir ögeyi dahil etmek istersek:
// using std::cout;
int main() {
[[maybe_unused]] int a = 5; // copy initialization
int b(5); // direct initialization
int c{5}; // list initialization — narrowing’a izin vermez
}
-
std::cin >>operatörü boşluk karakterine kadar okurken, -
std::getline(cin, str)satır sonuna (veya belirlediğiniz başka bir sınırlayıcıya) kadar tüm girdi satırını alır. Bu sayede kullanıcıdan boşluk içeren satırlar veya tüm satırı almamız gerektiğinde getline tercih edilir. -
namespace, aynı isimli tanımlamaların çakışmasını önlemek için kullanılır.- Hem değişken, hem fonksiyon, hem de sınıf ve diğer tanımları ayrı gruplarda toplayabiliriz.
- İç içe namespace’ler tanımlamak da mümkündür.
constexpr, derleme zamanında hesaplanabilen ve kesinlikle sabit (compile-time constant) olan değerler için;constise derlendikten sonra değiştirilemeyen, ama derleme zamanında mutlaka hesaplanamayabilecek değerler için kullanılır- C++20 ile aggregate tipler için “designated initializer” desteği eklendi. Böylece yapıdaki sadece istediğiniz üyeyi atayabilirsiniz:
typedefEski C/C++ tarzı tip takma adı (alias) oluşturma.-
usingC++11 ile gelen, daha okunur ve şablonlarla da çalışabilen modern alias tanımı. -
Öne sıfır koymak: oktalık (ör. 012); ekrana oktal gösterimi için std::oct.
- Öne 0x koymak: onaltılık (ör. 0x12); ekrana onaltılık için std::hex.
- Öne 0b koymak: ikilik (ör. 0b10).
- C++14+’te büyük sayılarda okuryazılığını artırmak için tırnak:
100'000'000.
Döngüler ve Kontrol Yapıları
C++’ta klasik kontrol yapılarının yanı sıra range-based for (C++11) döngüsü de bulunur.
for (init; cond; inc),while (cond),do { … } while (cond);if (cond) { … } else { … }switch (expr) { case …: …; break; … }goto label;(genellikle önerilmez; kod akışını karmaşıklaştırır)
Programı Sonlandırma ve Hata Denetimi
std::exit(int status):Programı “normal” olarak sonlandırır.std::atexit(func):Program kapanırken func()’u çağırır.std::abort():Programı aniden, “abnormal” biçimde sonlandırır.assert(cond):cond sağlanmazsa programı durdurur (yalnızca NDEBUG tanımlı değilken).
Fonksiyonlar ve Inline Namespace
- inline fonksiyon: Derleme aşamasında çağrıldığı yere yerleştirilir (inlining), fonksiyon çağrısı yükünü azaltır.
- inline namespace: Birden fazla sürüm içeren kütüphanelerde, öntanımlı sürümü belirtmek için:
#include <iostream>
namespace V1 {
void doSomething() { std::cout << "V1\n"; }
}
inline namespace V2 {
void doSomething() { std::cout << "V2\n"; }
}
int main() {
V1::doSomething(); // V1
V2::doSomething(); // V2
doSomething(); // inline namespace → V2
}
- constexpr vs. consteval vs. constexpr
- constexpr: Derleme zamanında hesaplanabilir, fakat ihtiyaç duyulduğunda çalışma zamanında da çağrılabilir.
- consteval: Her çağrısı derleme zamanında kesinlikle değerlendirilir (C++20).
Lambda İfadeleri
- Anonim fonksiyon tanımı yapar:
- Parametre ve dönüş:
- Yakalama listesi
[=]tüm yerel değişkenleri değer ile kopyalar[&]tüm yerel değişkenlere referans verir[a, &b]belli değişkeni değer, diğerini referans alır- mutable ile değer yakalansa bile içerde değiştirme izinli olur ama dışarı etkilemez
int a = 1, b = 2;
auto lv = [=]() mutable { a = 5; return a; }; // dışarıdaki a değişmez
auto lf = [&]() { b = 5; return b; }; // dışarıdaki b değişir
Şablonlar (Templates)
- C++’ta türden bağımsız kod yazmak için kullanılır.
- Eğer tüm argümanlar aynı türden ise < > yazmaya gerek yoktur.
- Farklı türler için genellikle türleri kendiniz belirtirsiniz.
- Sınıf Şablonları ve Varsayılan Argüman
#include <iostream> #include <typeinfo> template<typename T, typename U = int> class MyClass { public: MyClass() { T value{}; std::cout << typeid(value).name() << '\n'; } template<typename X> void add(X a, X b) { std::cout << (a + b) << '\n'; } }; int main() { MyClass<double> m1; // U = int MyClass<char, long> m2; // açık belirtildi m1.add(1.2, 3.4); m1.add<double>(5.5, 6.6); }
Bitset
#include <bitset>
bitset<5> bits; // 5 bitlik bir dizi
cout << bits << endl; // 00000
bits = 10;
cout << bits << endl; // 01010
Dinamik Bellek
char* buffer = new char[8]; // Bellekten dizi ayırma
delete[] buffer; // Dizi silme
const int* ptr1; // İşaret ettiği değer sabit, adres değişebilir
int* const ptr2; // Adres sabit, işaret ettiği değer değişebilir
int (*array)[5] = new int[x][5]; // x×5’lik matris
Smart Pointers
C++’ta ham işaretçiler (new/delete) yerine akıllı işaretçiler (smart pointers) kullanmak, bellek sızıntılarını ve çifte silme hatalarını büyük oranda ortadan kaldırır. Üç ana türü vardır:
1. std::unique_ptr<T> Tek sahipli akıllı işaretçidir. Sahip olduğu nesnenin bellekten silinmesini otomatikleştirir: unique_ptr kapsam (scope) sonlandığında delete çağrılır. Kopyalanamaz, ancak taşınabilir (std::move ile). Bu sayede çifte silme riskini ve bellek sızıntılarını önler. İsterseniz özel bir silici (deleter) de tanımlayabilirsiniz:
auto fileCloser = [](FILE* f){ if(f) fclose(f); };
std::unique_ptr<FILE, decltype(fileCloser)> fptr(fopen("log.txt","r"), fileCloser);
-
std::shared_ptr<T>Paylaşımlı sahiplik sağlayan işaretçidir. Aynı nesneye birden fazla shared_ptr işaret edebilir ve referans sayısı (use_count) sıfırlanana dek nesne silinmez. Döngüsel bağımlılık riskini kırmak için std::weak_ptr kullanarak “zayıf” işaretçi oluşturabilirsiniz. Referans sayısını yönetmek için atomik işlemler kullandığından, unique_ptr’a göre biraz daha maliyetlidir. -
std::make_unique<T>(...)vestd::make_shared<T>(...)C++14/17 ile gelen fabrikalar (factory functions). Ham işaretçi yerine doğrudan akıllı işaretçi oluşturur ve exception safety (istisna güvenliği) sağlar:
auto up = std::make_unique<MyClass>(ctorArg1, ctorArg2);
auto sp = std::make_shared<MyClass>(ctorArg1, ctorArg2);
- make_unique: yalnızca bir sahipli unique_ptr döndürür.
- make_shared: nesneyi ve referans sayacı tek bir bellek bloğunda tutar, daha verimli bellek kullanımı sunar.
Casting Türleri
- static_cast
(x): Derleme zamanında güvenli dönüşümler (örneğin sayı türleri arası). - dynamic_cast
(p): Çalışma zamanında polimorfik sınıflar arasında güvenli downcast/upcast. - const_cast
(x): const niteliğini kaldırmak için. - reinterpret_cast
(p): İki iş parçacığı arasındaki bellek gösterimini yeniden yorumlamak için (çok dikkatli kullanılmalı).
float f = 3.14f;
int i1 = static_cast<int>(f);
class Base { virtual void foo() {} };
class Derived : public Base {};
Base* bp = new Derived();
Derived* dp = dynamic_cast<Derived*>(bp);
const int x = 5;
int& y = const_cast<int&>(x);
int* p = reinterpret_cast<int*>(0x1234);
std::vector vs. std::array
C++’ta dinamik ve sabit boyutlu diziler için iki temel sınıf şablonu vardır:
std::vector<T>- Dinamik boyutlu dizi. Eleman ekledikçe otomatik büyür.
- Rastgele erişim için
operator[]ve sınır denetimliat()sağlar. vec[i]hızlı ama sınır denetimsiz.vec.at(i)sınır dışı erişimde std::out_of_range fırlatır.
#include <vector>
#include <iostream>
int main() {
std::vector<int> primes{2, 3, 5, 7}; // Başlangıç listesiyle 4 eleman
std::vector<int> data(10); // 10 elemanlı, tüm değerler 0
// Hatalı: doğrudan tek sayıyla vektör oluşturulamaz
// std::vector<int> v1 = 10;
// Doğru: tek elemanlı vektör
std::vector<int> v1{10};
// Erişim
std::cout << primes[1] << "\n"; // 3
std::cout << v1.at(0) << "\n"; // 10
// Boyut öğrenme
std::cout << "Size: " << v1.size() << "\n";
std::cout << "Capacity: " << v1.capacity() << "\n";
}
-
std::array<T, N>- Sabit boyutlu dizi; derleme zamanında N belirlenir.
- İçinde C stili dizilere benzer şekilde çalışır, ama STL ile uyumludur.
size(),at(),operator[],begin(),end()gibi üyelere sahiptir.
-
empty():Boşsa true, değilse false döner. size():Geçerli eleman sayısını döner.capacity():Ayrılmış bellek kapasitesini döner; size() ≤ capacity().reserve(n):Kapasiteyi en az n olacak şekilde önceden ayırır; yeniden tahsisi azaltır.resize(n):Boyutu n olarak ayarlar; yeni elemanlar varsayılan T ctor ile oluşturulur.push_back(val):Sonuna bir kopya ekler.emplace_back(args…):Nesneyi yerinde (in-place) oluşturur; kopya maliyeti yok.pop_back():Son elemanı siler.front() / back():İlk ve son elemanı referans olarak döner.
#include <vector>
#include <iostream>
int main() {
std::vector<int> v;
std::cout << std::boolalpha << "Empty? " << v.empty() << "\n";
v.reserve(5); // Kapasite ≥ 5
for (int i = 1; i <= 5; ++i) {
v.emplace_back(i * 10); // 10, 20, 30, 40, 50
}
std::cout << "Size: " << v.size() << "\n"; // 5
std::cout << "Capacity: " << v.capacity() << "\n";
v.resize(3); // artık {10,20,30}
std::cout << "After resize: ";
for (auto x : v) std::cout << x << ' ';
std::cout << "\n";
v.push_back(99); // {10,20,30,99}
std::cout << "Last element: " << v.back() << "\n";
v.pop_back(); // son elemanı kaldırır
std::cout << "After pop: ";
for (auto x : v) std::cout << x << ' ';
std::cout << "\n";
}
Nesne Yönelimli Programlama (OOP)
-
Erişim Belirleyicileri (Access Specifiers)
public: Her yerden erişilebilir.protected: Sadece o sınıf içinden ve ondan türeyen alt sınıflardan erişilebilir.private: Yalnızca tanımlandığı sınıfın içinden erişilebilir. (Varsayılan erişim seviyesi sınıf (class) içinde private’dır.)
-
Özel Üye Fonksiyonlar:
Default,Delete,Special Members- C++ derleyici, sınıfınız için eğer belirtmezseniz aşağıdakileri “default” olarak oluşturur:
- Varsayılan yapıcı (default constructor)
- Yıkıcı (destructor)
- Kopya yapıcı (copy constructor)
- Atama operatörü (copy assignment operator)
class MyClass { public: MyClass(int x) : value(x) {} // Özel yapıcı MyClass() = default; // Derleyici yapıcıyı oluşturursun MyClass(const MyClass&) = delete; // Kopyalamayı yasakla MyClass& operator=(const MyClass&) = delete; // Atamayı yasakla ~MyClass() = default; // Varsayılan yıkıcı private: int value; };
-
thisİşaretçisi ve Başlatıcı Listesithis, içinde bulunduğunuz nesnenin adresini gösteren işaretçidir.- Üye başlatma listesi (
initializer list) ile, yapıcı gövdesine girmeden önce üye değişkenlerinizi atayabilirsiniz; böylece çakışan isimlerde de netlik sağlanır:
-
Kapsülleme (Encapsulation)
- Sınıfın iç verilerini private tutup, public getter/ setter metotlarıyla korumalı erişim sağlarsınız:
-
Static Üyeler
- static üye değişken ve fonksiyonlar sınıfa ait, nesneye değil.
- static üye fonksiyonlar sadece başka static üyelere erişebilir.
- Tanımı sınıf dışına bir kez yapılmalıdır:
-
Friend (Arkadaş) Bildirimi
friendfonksiyon veya sınıflar, private/protected üyelere erişebilir:
-
Operatör Aşırı Yükleme (Operator Overloading)
- Sınıfınızda var olan operatörleri özelleştirebilirsiniz; ancak tüm operatörler yüklenemez (sizeof, ::, .* vb. yasaktır).
class Vec { int x, y; public: Vec(int x, int y) : x(x), y(y) {} Vec operator+(const Vec& r) const { return Vec{x + r.x, y + r.y}; } Vec& operator+=(const Vec& r) { x += r.x; y += r.y; return *this; } friend std::ostream& operator<<(std::ostream& os, const Vec& v) { return os << "(" << v.x << ", " << v.y << ")"; } };
- Sınıfınızda var olan operatörleri özelleştirebilirsiniz; ancak tüm operatörler yüklenemez (sizeof, ::, .* vb. yasaktır).
-
constÜyeler ve mutableconstüye fonksiyonlar (void f() const) sınıf verilerini değiştirmez.mutableile işaretlenmiş üye değişkenler, const fonksiyonlar içinde bile değiştirilebilir:
-
explicitYapıcılar- Tek parametreli yapıcılar için explicit koyarak istenmeyen otomat dönüşümleri önlersiniz:
-
Kalıtım (Inheritance)
- Tekli kalıtım: class Derived : access Base { … };
- Erişim: public, protected veya private (default private).
- Virtüel kalıtım (diamond problemini çözer):
-
Polimorfizm (Çok Biçimlilik)
- virtual üye fonksiyonlar, çağrının gerçek nesne türüne göre çözülmesini sağlar.
- Saf sanal fonksiyon (pure virtual) ile soyut sınıf (interface) oluşturabilirsiniz:
QT
Mesaj Yapısı (Event Loop)
- Her Qt uygulamasının veya thread’in bir mesaj kuyruğu (event queue) vardır.
- GUI, sisteme gelen olayları (tıklama, klavye girişi vb.) mesaj formunda kuyruğa iletir.
- Uygulama,
app.exec()çağrısıyla mesaj döngüsünü başlatır ve mesaj yoksa bekler, mesaj geldikçe ilgili widget’a iletir.
#include <QApplication>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget window;
window.show(); // Pencereyi gösterir
return app.exec(); // Mesaj döngüsünü başlatır
}
Log Mesajları
#include <QDebug>
qInfo() << "Bilgi mesajı";
qDebug() << "Debug mesajı" << 123;
qWarning() << "Uyarı mesajı";
qCritical()<< "Hata mesajı";
qFatal("Kritik hata, program sonlanacak"); // Çıkışı *abnormal* yapar
Kod Tarzı ve İsaretleme
- Qt kodlama stilinde sınıf üye değişkenleri için genellikle m_ öneki kullanılır (Hungarian Notation’ın hafif bir uyarlaması):
connect(sender, SIGNAL(valueChanged(int)),
receiver, SLOT(onValueChanged(int)));
disconnect(...);
Temel Qt Sınıfları
QPushButtonButon oluşturur. Konum ve boyut ayarı için move(x,y) ve resize(w,h) kullanılır.QLabelMetin veya HTML biçimlendirmeli içerik gösterirQMessageBoxBilgi, uyarı veya hata kutularıQStringUnicode destekli metin sınıfı. Metotlar:insert(),remove(),split(),toInt(),toDouble()vb.QCharTek bir Unicode karakter. Kontroller:isLower(),isUpper(),isDigit()dönüşümler:toLower(),toUpper().QVector<T>/QList<T>/QStringList/QSet<T>/QMap<Key,Val>qDeleteAll(container)İşaretçi içeren konteynerlerde içindeki işaretçileri siler.QIODeviceTemel giriş/çıkış arabirimi.QFileDosya işlemleri. open(), readAll(), write().QFileInfoDosya/dizin bilgisi: fileName(), filePath(), isFile(), size(), suffix().QDirDizin yönetimi: cd(), cdUp(), mkdir(), exists().QTextStreamMetin akışları için; Unicode destekli << / >>.QDataStreamSeri (binary) akışlar için, platformlar arası uyumlu.QStorageInfoDosya sistemindeki disk/partition bilgileri.QLockFileDosya kilidi; çoklu işlemde güvenlik sağlar.QSysInfoSistem bilgisi (OS tipi, mimari).QFileSystemWatcherDizin/dosya değişikliklerini izler.QProcessHarici süreçleri başlatır ve iletişim kurar.QSettingsAyarları anahtar-değer olarak saklar (Windows registry veya ini/plist dosyaları).QByteArrayViewSalt okunur QByteArray görünümü; kopya olmadan erişim.QScopedPointer<T>Tek sahipli işaretçi. Kapsam sonlandığında nesneyi siler.QSharedPointer<T>Paylaşımlı işaretçi, referans sayımlı. Son kullanıcı silindiğinde nesneyi serbest bırakır.QHBoxLayout,QVBoxLayout,QGridLayoutWidget’ları yatay, dikey veya ızgara düzeninde yerleştirir.QTimerBelirli aralıklarla sinyal (timeout()) yayar:QThreadArka plan iş parçacığı oluşturur.- Öncelik
HighestPriority,LowestPriorityvb. QMutexPaylaşılan veri erişiminde kilitleme için lock(), unlock().
Qt Veri Tipleri
C++ & QML Haberleşmesi
-
Meta-Object System (MOC)
- Qt’nin sinyal-slot,
Q_PROPERTY, dinamik tür bilgisi (RTTI) gibi uzantılarını sağlayan araçtır. - Her QObject türevi sınıfa
Q_OBJECTmakrosu eklenmeli; ardından moc (Meta-Object Compiler) bu sınıf için ek kod üretir. - MOC çıktısı derleyiciye eklenerek sinyal-slot bağlama, öz nitelik (property) kaydı vb. işler otomatik hale gelir.
- Qt’nin sinyal-slot ve dinamik özelliğini sağlayan aracı.
- Her QObject türevindeki sınıfa
Q_OBJECTmakrosunu ekleyerek MOC’un işlevselliğini aktifleştirirsiniz. - Qt’nin sinyal-slot, Q_PROPERTY, dinamik meta-veri gibi özellikleri formlar
- Q_OBJECT makrosunu eklediğiniz sınıflar için otomatik olarak ek kod üretir.
- Sınıfınıza sinyal, slot, property tanımları eklediğinizde, MOC bunları yürütebilecek C++ kaynaklarını oluşturur.
- Derleyiciye eklenen bu MOC çıktısı, Qt’nin meta-object altyapısının temelidir.
- MOC olmasaydı, connect(), emit, Q_PROPERTY gibi üst seviye mekanizmalar çalışmazdı.
- Kaynak dosyanızı derlerken, Qt’nin build sistemi otomatik olarak moc_MyClass.cpp gibi ek dosyalar üretir ve bu dosyalar da derlemeye dahil edilir.
- Qt’nin sinyal-slot,
-
Signals & Slots
- Signal: Nesnede bir olay gerçekleştiğinde duyurulan bildiridir; parametre taşıyabilir.
- Slot: Bir sinyal tetiklendiğinde çağrılan normal C++ üye fonksiyonu veya lambda.
- Bu mekanizma, nesnelerin birbirinden habersiz çalışmasını (“loosely coupled”) sağlar
connect(sender, &Sender::valueChanged, receiver, &Receiver::onValueChanged); // Function pointers (C++11+) //Derleme zamanında değil, çalışma zamanında çözülür; yazım hatası ancak runtime’da fark edilir. connect(sender, SIGNAL(valueChanged(int)), receiver, SLOT(onValueChanged(int))); // SIGNAL/SLOT makroları (eski stil) connect(button, &QPushButton::clicked, this, [this]{ doSomething(); }); // Lambda / Functor emit valueChanged(m_value); // Signal tetiklemek için
-
Q_PROPERTY- C++ tarafında tanımladığınız bir üye değişkeni, getter/setter ve notifikasyon sinyaliyle QML’e “property” olarak sunar
- READ: getter fonksiyonu
- WRITE: setter fonksiyonu
- NOTIFY: değer değiştiğinde yayınlanacak sinyal
-
QQmlContext & Context Properties
setContextProperty(name, obj)QML kök bağlamına (root context) name adıyla obj’i yerleştirir.- C++ nesnelerini doğrudan QML’de isimle kullanmak için:
main.cpp main.qml
-
qmlRegisterType & Singleton
qmlRegisterSingletonInstance(uri, ver, name, instance)Önceden oluşturduğunuz tekil C++ nesnesini QML global singleton olarak sunar.qmlRegisterType<T>(uri, ver, name)QML kodunda doğrudan import uri ver → name { } ile kullanılmasını sağlar.qmlRegisterUncreatableTypeQML’den yeni örneği oluşturulamayan, yalnızca sabit tanımlı özelliklerine erişilen C++ tipleri için kullanılır.qRegisterMetaTypeSignal-slot ve QVariant aracılığıyla aktarılacak custom tipler için çalışma zamanı tipi kaydı yapar.
-
QVariantve Metatype SistemiQVariantHer türü(int, QString, QObject*, custom type…)saklayabilen kapsayıcı. QML-C++ arası veri taşımada kritik.- Custom C++ tiplerini QVariant içinde kullanmak için:
Q_GADGETQObject mirası gerektirmeyen, yine deQ_PROPERTY+ QMetaType desteği sağlayan sınıflar için:
-
Q_INVOKABLE -
QVariantList, Model-View,ListModelQVariantList: QML’de dizi (ListModel) olarak kolay kullanılabilir.- MVC mimarisi:
QAbstractListModeltüreterek veri modelinizi tanımlayıp QML’de ListView/Repeater ile bağlayabilirsiniz.
-
Event Loop & Mesaj Döngüsü
QCoreApplication::exec()veyaQQmlApplicationEngine::exec()ile başlatılır; GUI ve sinyal-slot etkileşimini besleyen ana döngüdür.
-
qt_add_qml_module- Qt 6+ projelerinde, QML kaynaklarını ve bileşenlerini modül halinde derlemek için kullanılır:
- URI: QML’de import MyApp.Components 1.0 ile erişilen ad.
- QML_FILES: Modülün içindeki .qml dosyaları.
- RESOURCE_PREFIX: QML’den çağırırken kullanılacak yol.