C++ Notlarım
Aşağıda C++ ile ilgili aldığım notlar var.
C++11
C++11 veya C++03 desteğini etkinleştirmek için -std=c++0x ve -std=c++1y seçeneklerini kullanmak gerekir.
array
çok boyutlu array aşağıdaki gibi ilklendirilebilir.
Değişkenin tipini belirtmeden derleyicinin belirlemesi sağlanır. Buradaki soruda auto * şeklinde kullanım da gösterilmiş.
Bence sadece auto şeklinde kullanma amaca daha iyi hizmet eder.
const değişken
Buradaki cevapta değişkenin adresi alınmadığı müddetçe const int veya #define ile bir değişken tanımlamanın modern derleyiciler için aynı şey olduğu belirtilmiş.
Eski C++ ile integral olmayan static const değişkenleri sınıfın özelliği gibi tanımlamak mümkün değildi. Bu yüzden aşağıdaki gibi yapmak gerekiyordu.
C++11 ile artık daha kolay. Örnek:
constructor
buit-in tiplerin constructor metodu yoktur
C++'ta built-in tiplerin constructor metodları yoktur.
int a = 42 ve
int a;
a = 42 aynı şeydir. a tipinin constructor metodu olmadığı için a tipini tanımlayan ilk cümle bir şey çalıştırmaz.
constructor'dan virtual metod çağrılamaz
Genel kural olarak bir sınıfın contructor veya destructor metodlarında virtual metodlar çağrılmaz. Örneğin parasoft şu uyarıyı verir.
"A class's virtual functions shall not be invoked from its destructor or any of its constructors (JSF-71.1-2)"
Örnekte pure virtual bir metod çağrıldığı için çöker.
constructor'ın adresi alınamaz
constructor ve destructor metodlarının adresleri alınamaz.
"References and pointers cannot be used on constructors and destructors because their addresses cannot be taken."
Örnek:
ilklendirme sırası
Sınıfın değişkenleri constructor'da deklare edildikleri sırada ilklendirilirler. Eğer constructor içinde deklare edildikler sırada kullanılmazlarsa gcc aşağıdakine benzer bir hata verir.
copy constructor
Bir nesne diğer bir nesneye eşitlenerek yaratılırsa copy constructor çağırılır. Örnek:
Assignment operatörünün çağırılıp çağırılmayacağını anlamanın en kolay yolu = işaretinden önce g değişkenin tanımlanıp tanımlanmamış olduğuna bakmak.
Copy constructor list initialization gibi de çağırılabilir. Örnek:
Bazı durumlarda copy constructor çağırılmayabilir. Örnekler:
Eğer metod içinden dönen ve ismi olan nesne bir başka nesneyi ilklendirmek için kullanılıyorsa. Yani named return value optimization varsa. Örnek:
covariant return type
C++ covariant return type yöntemini destekliyor. Yani virtual bir metod A tipini döndürüyorsa, bu metodu yeniden gerçekleştiren bir başka metod A'dan türeyen B tipini döndürebilir. Bu yöntem Java'da da var.
decltype
Bu operatörün ne işe yaradığını ben de hiç bir zaman tam olarak anlamadım. Sanırım bir tip tanımlamaya yarıyor. Örnek:
default constructor
Eğer sınıfın herhangi bir constructor metodu varsa, derleyici default constructor'ı otomatik olarak tanımlamaz.
constructor chaining
default constructor'lar otomatik olarak "constructor chain" işlemine tabidirler. Yani derleyici otomatik olarak bir üst sınıfın default constructor metodunu bizim için çağırır.
template
Default constructor'a template parametresi geçmek imkansızdır. Örnekte geçilen template sınıfa verilir.
destructor
Derleyici biz destructor yazmasak bile "implicit declared" bir destructor üretir. Kendimiz boş bir tane yazarsak bu "user declared" olarak adlandırılıyor. İkisi arasında tam ne fark var bilmiyorum.Bir sınıfın her zaman heap'te yaratılmasını "delete"edilmemesini istiyorsak, sınıfa pure virtual bir destructor tanımlayabiliriz.
Destructor içinde virtual metodlar kullanılamaz! Ancak this-> kelimesi kullanılabilir. Ayrıca Destructor hiç bir zaman exception atmamalıdır!
dynamic_cast
Multiple inheritance olduğu durumda nesneyi kalıttığı sınıflardan birine döndürmek için kullanılır. Eğer dönüşüm başaralı olmazsa dynamic_cast NULL değeri döner. dynamic_cast kullanabilmek için RTTI seçeneği ile derlemek gerekir.
Visual Studio ile RTT desteğini kapatmak için projeye sağ tıklayıp Properties / C/C++ / Language / Enable Run-Time Type Information seçeneği değiştirilmeli.
explicit constructor
Derleyicinin bir nesneyi yaratmak için kendi kendine verilen parametrenin tipini değiştirmesi engellemek demek. Örnek:
explicit aynı zamanda conversion metodların imzasında da kullanılabilir. Örnek:
Bir translation unit bir başka translation unit içinde tanımlı değişkeni kullanabilir. Örnek'te bir başka .c dosyasında tanımlı olan değişken kullanılıyor.
friend class başka bir sınıfın private herşeyine erişebilir. Başka bir namespace içinde sınıf friend yapılmak istenirse önce forward friend class declaration yapılması gerekebilir. Örnek:
namespace NamespaceB {
class ClassB;
};
namespace NamespaceA {
class ClassA {
friend class NamespaceB::ClassB;
//Other methods...
}
};
function reference
function reference ve function pointer aynı işlevleri görürler. Sadece yazımları farklı. Ancak function reference hemen hiç kullanılmaz.
function pointer
Aşağıda parametre almayan bir function pointer örneği var.
Function pointer decay özelliğinden dolayı istersek
Member function pointer
member function pointer aşağıdaki gibi çağırılır.
Functor
Functor, operator() metodunu tanımlayan bir sınıf. Her sınıfta olduğu gibi istenirse state saklamak mümkün. Bu durum, functional programming felsefesini ihlal etse de C++ bu esnekliği sağlıyor. Örnek:
Lambda
Lambda kullanmak için [] (parametreler) {...} şeklinde kodlama yapmak lazım. Bazı diğer dillerde lambda'ya closure da deniliyor. Örneğin groovy dilinde closure biraz daha farklı tanımlanıyor. Örnek:
Aşağıda C++ ile ilgili aldığım notlar var.
C++11
C++11 veya C++03 desteğini etkinleştirmek için -std=c++0x ve -std=c++1y seçeneklerini kullanmak gerekir.
array
çok boyutlu array aşağıdaki gibi ilklendirilebilir.
float y[3][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 }
};
auto değişkenDeğişkenin tipini belirtmeden derleyicinin belirlemesi sağlanır. Buradaki soruda auto * şeklinde kullanım da gösterilmiş.
Bence sadece auto şeklinde kullanma amaca daha iyi hizmet eder.
const değişken
Buradaki cevapta değişkenin adresi alınmadığı müddetçe const int veya #define ile bir değişken tanımlamanın modern derleyiciler için aynı şey olduğu belirtilmiş.
#define STD_VEC_HINT 6;
const int stdVecHint = 6;
constexprEski C++ ile integral olmayan static const değişkenleri sınıfın özelliği gibi tanımlamak mümkün değildi. Bu yüzden aşağıdaki gibi yapmak gerekiyordu.
C++11 ile artık daha kolay. Örnek:
constructor
buit-in tiplerin constructor metodu yoktur
C++'ta built-in tiplerin constructor metodları yoktur.
int a = 42 ve
int a;
a = 42 aynı şeydir. a tipinin constructor metodu olmadığı için a tipini tanımlayan ilk cümle bir şey çalıştırmaz.
constructor'dan virtual metod çağrılamaz
Genel kural olarak bir sınıfın contructor veya destructor metodlarında virtual metodlar çağrılmaz. Örneğin parasoft şu uyarıyı verir.
"A class's virtual functions shall not be invoked from its destructor or any of its constructors (JSF-71.1-2)"
Örnekte pure virtual bir metod çağrıldığı için çöker.
struct Base
{
Base() { method(); }
virtual void method() = 0;
};
struct Derived : Base
{
void method() {};
};
int main()
{
Derived d;
}
Bu kural Java için, geçerli olmasa da hataya açık kapı bıraktığı için, yapılmaması bence daha iyi. Örnek de hatalı durum görülebilir.constructor'ın adresi alınamaz
constructor ve destructor metodlarının adresleri alınamaz.
"References and pointers cannot be used on constructors and destructors because their addresses cannot be taken."
Örnek:
ilklendirme sırası
Sınıfın değişkenleri constructor'da deklare edildikleri sırada ilklendirilirler. Eğer constructor içinde deklare edildikler sırada kullanılmazlarsa gcc aşağıdakine benzer bir hata verir.
Field1 will be initialized after Field2.Dolayısıyla dışarıdan verilen parametreyi kullanma daha doğrudur. Örnek'te mSpeed mEntity'den daha önce ilklendirilir.
class Foo {
public:
Foo(int speed) :
mSpeed(speed),
mEntity(speed)
{ }
private:
int mSpeed;
Entity mEntity;
}
copy constructor
Bir nesne diğer bir nesneye eşitlenerek yaratılırsa copy constructor çağırılır. Örnek:
Assignment operatörünün çağırılıp çağırılmayacağını anlamanın en kolay yolu = işaretinden önce g değişkenin tanımlanıp tanımlanmamış olduğuna bakmak.
Copy constructor list initialization gibi de çağırılabilir. Örnek:
Demo Clone() {veya
return Demo{ *this };
}
Demo Clone() {Copy constructor'ı etkinsizleştirmek için iki yöntem var. İlkinde metod imzası tanımlanır ancap .cpp dosyasında metod yazılmaz.
return {*this};
}
private:veya C++11 ile
MyClass(const MyClass& that);
MyClass(const MyClass& that) = delete;copy Constructor Elision
Bazı durumlarda copy constructor çağırılmayabilir. Örnekler:
Eğer metod içinden dönen ve ismi olan nesne bir başka nesneyi ilklendirmek için kullanılıyorsa. Yani named return value optimization varsa. Örnek:
covariant return type
C++ covariant return type yöntemini destekliyor. Yani virtual bir metod A tipini döndürüyorsa, bu metodu yeniden gerçekleştiren bir başka metod A'dan türeyen B tipini döndürebilir. Bu yöntem Java'da da var.
decltype
Bu operatörün ne işe yaradığını ben de hiç bir zaman tam olarak anlamadım. Sanırım bir tip tanımlamaya yarıyor. Örnek:
Eğer sınıfın herhangi bir constructor metodu varsa, derleyici default constructor'ı otomatik olarak tanımlamaz.
constructor chaining
default constructor'lar otomatik olarak "constructor chain" işlemine tabidirler. Yani derleyici otomatik olarak bir üst sınıfın default constructor metodunu bizim için çağırır.
template
Default constructor'a template parametresi geçmek imkansızdır. Örnekte geçilen template sınıfa verilir.
destructor
Derleyici biz destructor yazmasak bile "implicit declared" bir destructor üretir. Kendimiz boş bir tane yazarsak bu "user declared" olarak adlandırılıyor. İkisi arasında tam ne fark var bilmiyorum.Bir sınıfın her zaman heap'te yaratılmasını "delete"edilmemesini istiyorsak, sınıfa pure virtual bir destructor tanımlayabiliriz.
Destructor içinde virtual metodlar kullanılamaz! Ancak this-> kelimesi kullanılabilir. Ayrıca Destructor hiç bir zaman exception atmamalıdır!
dynamic_cast
Multiple inheritance olduğu durumda nesneyi kalıttığı sınıflardan birine döndürmek için kullanılır. Eğer dönüşüm başaralı olmazsa dynamic_cast NULL değeri döner. dynamic_cast kullanabilmek için RTTI seçeneği ile derlemek gerekir.
Visual Studio ile RTT desteğini kapatmak için projeye sağ tıklayıp Properties / C/C++ / Language / Enable Run-Time Type Information seçeneği değiştirilmeli.
explicit constructor
Derleyicinin bir nesneyi yaratmak için kendi kendine verilen parametrenin tipini değiştirmesi engellemek demek. Örnek:
void DoBar (Foo foo)Aşağıdaki örnekte explicit olmayınca "conversion constructor"'ın çağrıldığı görülebiliyor.
{
int i = foo.GetFoo ();
}
int main ()
{
DoBar (42);//Foo'nun int alan constructor metodu otomatik çağırılır
}
Çıktı olarak "Y(int)" verir.
explicit aynı zamanda conversion metodların imzasında da kullanılabilir. Örnek:
explicit operator bool() const ;extern
Bir translation unit bir başka translation unit içinde tanımlı değişkeni kullanabilir. Örnek'te bir başka .c dosyasında tanımlı olan değişken kullanılıyor.
extern int var;
int main(void)
{
var = 10;
return 0;
}
friendfriend class başka bir sınıfın private herşeyine erişebilir. Başka bir namespace içinde sınıf friend yapılmak istenirse önce forward friend class declaration yapılması gerekebilir. Örnek:
namespace NamespaceB {
class ClassB;
};
namespace NamespaceA {
class ClassA {
friend class NamespaceB::ClassB;
//Other methods...
}
};
function reference
function reference ve function pointer aynı işlevleri görürler. Sadece yazımları farklı. Ancak function reference hemen hiç kullanılmaz.
void (&fr)() = foo;
fr();
veyavoid (*fp)() = &foo;
fp();
function pointer
Aşağıda parametre almayan bir function pointer örneği var.
Function pointer decay özelliğinden dolayı istersek
pf p1 = &fun;şeklinde de yazabilirdik. Yani tanımlı bir function, tıpkı array'lerde olduğu gibi otomatik olarak pointer'a çevrilebiliyor.
Member function pointer
member function pointer aşağıdaki gibi çağırılır.
(d.*f)(5);
(p->*f)(5);
Functor
Functor, operator() metodunu tanımlayan bir sınıf. Her sınıfta olduğu gibi istenirse state saklamak mümkün. Bu durum, functional programming felsefesini ihlal etse de C++ bu esnekliği sağlıyor. Örnek:
Lambda
Lambda kullanmak için [] (parametreler) {...} şeklinde kodlama yapmak lazım. Bazı diğer dillerde lambda'ya closure da deniliyor. Örneğin groovy dilinde closure biraz daha farklı tanımlanıyor. Örnek:
printMapClosure = { key, value -> println key + "=" + value }Lambda derleyici tarafından, functor'a çevirilir. Böylece lambda state bilgisini yakalayabilir.
Lambdalar function isteyen herhangi bir metoda geçilebilir. Örnek:
Hiç parametre almayan lambda örneği.
Lambdaların return type tanımlamadığına dikkat! Return type yerine auto kelimesi kullanılıyor. Derleyici döndürülen parametre tipini kendisi bulur.
auto func = [] () { cout << "Hello world"; };Tek parametre alan lamda örneği
auto func = [] (const string& addr) { return addr.find( ".org" ) != string::npos; }Lambda ve Reference
Lambda herşeyi "by value" olarak yakalar.
LValue
İsmi olan değişken gibi düşünülebilir. Örnek'te #define max 10 ile max lvalue olmayınca ++ operatörünün hata vereceği gösterilmiş.
LValue kullanan bir başka örneği aşağıdaki gibi çağırabiliriz:
int& get( int* array, int index ) { return array[index]; }
get( array, 5 ) = 5;
Assignment operatörü de lvalue döner. (a = b)++ işleminde a'nın değeri artar.
Move Constructor
Yazıyı buraya taşıdım.
Most Vexing Parse
Bu konuda en sinir bozucu parse olarak çevirilebilir. Vexation ile ilgili.Bir satırın değişken tanımlaması mı yoksa fonksiyon tanımlaması mı olduğunun ayırt edilememesi anlamına geliyor. Örnek:
Circle c2();//Deafault constructor mı yoksa metod mu ?
Bir başka örnek:
TimeKeeper time_keeper(Timer());//Hem Timer nesnesi alan bir değişken, hem de fonksiyon olabilir.Sınıf içinde sınıf tanımlamalarında da karşımızı çıkıyor. Örnek
Order of Evaluation
Metoda geçilen parametrelerin hangi sırada işleneceğinin sırası belirsiz olduğu için sonuçları da tanımsızdır. Derleyiciden derleyiciye değişebilir. Örnek:
f(i = 1, i = -1);
Eğer önce değişkenlerin değeri atanırsa sonra metod çağırılırsa hep -1 değeri geçilir.Bazı işlemlerin nasıl çalışacağı ise belirlenmiştir. Bu işlemere sequence point adı verilir. Örneğin comma operator bir sequence point'tir ve işlenmeye soldan başlanır. f (), g () çağrısında önce f () işletilir.
Order or Evaluation ve precedence aynı şeyler değildir! Aşağıdaki örnekte order or evaluation değil precedence devreye girer
milliVolts * 32767 * 32 / 1000 * 1024 / ticks * 2
Operator'lar
Konuyu C++ ve Operator başlıklı yazıya taşıdım.
Overloading
Konuyu Overloading başlıklı yazıya taşıdım.
Overloading ve Kalıtım
Konuyu Overloading başlıklı yazıya taşıdım.
POD Type
Konuyu C++ Notlarım POD başlıklı yazıya taşıdım.
RValue
RValue ismi olmayan ve adres operatorü ile erişilemeyen değer gibi düşünülebilir. Örnek:
int x = 3 + 4; ifadesinde 3+4 rvalue çünkü ifade bitince bu değerlere erişmenin yolu yok.
Burada da kural C++ gibi kodlanmış.
size_t
- Does it have a name ? lvalue : rvalue;
- Can I take the address of it ? lvalue : rvalue;
size_t unsigned bir değer döner. Örneğin bir çok veri yapısının count() metodu size_t döner. unsigned değer 0 ise, 0'dan 1 çıkartmak -1 yerine başka bir sonuç verir.
static kelimesi
Bir değişkeni veya C metodunu "internal linkage" yapar. Yani sadece kendi .cpp dosyası içinde erişilmesine izin verir.
static const yapılara değer atama
struct
static const olan bir struct'ın alanlarına istenirse ismen değer atanabilir.Örnek:
//.h fileprimitif veya komposit tip
struct mystruct {int field1;int field2};
//.cpp file
const static mystruct m = {field1 = 1, field2= 2};
Primitif tipler .h dosyasında veya .cpp dosyasında ilklendirilebilir. Ancak diğer değişkenler .cpp dosyasında ilklendirilmelidir.
array
array aşağıdaki gibi ilklendirilir. Örnek:
const c::p c::pp[2] = { {1,1},{2,2} };Eğer array'imiz struct yerine default constructor'ı olmayan bir class olsaydı, bu sefer array'i aşağıdaki gibi aşağıdaki gibi ilklendirirdik.
const c::Abc a[10] = { Abc(1), Abc(2), ..... };Eğer array'imiz struct yerine explicit olmayan constructor'lı bir class olsaydı, bu sefer array'i aşağıdaki gibi ilklendirirdik.
const c::Abc a[10] = { 1, 2, ..... };
static_assert
Derleme zamanında hata yakalanmasını sağlar. Bu iş için static_assert kullanılır. Çalışması şuna benzer. Eğer expr false ise büyüklüğü -1 olan bir array yaratılmaya çalışılır. Tabiki derleyici bunu derlemez ve hata verir.
Template ve Interface
Tuhaf olduğunu düşündüğüm bir yapı şöyle:
Template bir sınıf, aynı zamanda bir arayüzden türüyor. C++ ve STL içinde bu şekilde olan ve bence okuması zor olan bir kodlama şekli.
Variadic Function
Variadic Function değişken sayıda parametre alabilen metod anlamına gelir. Aşağıdaki şekilde kullanılır.
void myfunc(int count,...) {
va_list list;
va_start(list,count);
double value = va_arg(list, double)
va_end(list);
}
Aşağıda daha kolay olduğunu düşündüğüm bir yol var. Bu yöntemde aynı tipten parametreleri bir macro aracılığıyla array'a doldurup metod çağrısı yapılıyor.
void _actualFunction(type* values,int size) {
for (int index=0;index<size;index++ {
x = values[index];
//do whatever with x
}
}
#define callVariadicMethodSafely(values...) ({ type *v = { values }; _actualFunction(values, sizeof(v) / sizeof(*v)); })
C ve C++ arasındaki fark
C ve C++ arasında fark vardır. C dilinde bir metoda void yazılmaması, bu metodun değişken sayıda parametre alabileceği anlamına gelir. Parametre almayan metodlara void yazılması gerekir. Ancak C++ dilinde metoda parametre yazılmazsa kendiliğinden void olduğu farz edilir. Aradaki farkı gösteren bir örnek:
In c++
void fun();
means a function taking no arguments. To communicate that to C write
void fun(void); // also works in c++ but it's frowned upon
Parasoft NotlarımAşağıda Parasoft ile ilgili notlarım var.
Eğer parasoft pahalı geliyorsa, Visual Studio 2012'de Build / Run Code Analysis aracı da kısıtlı static analiz imkanı sunuyor.
Parasoft'u kullanmadan önce derleyicinin ürettiği tüm uyarıların (warning) temizlendiğinden emin olunmalı.
Parasoft ve Lisans
Lisans sunucusunu tanıtmak için Parasfot/Preferences menüsü seçilir. License nesnesi tıklanır. Host name ve Port number alanları doldurulur.
Parasoft/Licenses/Deactivate C++ Test ve Parasoft/Licenses/Activate C++ Test menüleri ile lisans alınıp geri verilebilir.
Example Configuration Ayarlanması
Visual Studio içinden Parasoft/Test Configurations menüsü seçilir. User-defined ağacı altındaki Example Configuration nesnesi tıklanır. Sağ tıklanarak "Duplicate" menüsü seçilir ve üzerinden deneme yapacağımız bir konfigürasyon yaratılır.
Rules
Static kod analizi için kullanılır. Static sekmesi seçilerek, Rules Tree sekmesinden tanımlı kurallardan işimize yarayanlar etkinleştirilir.
Metrics
Metrikler Number of Fields/Methods etrafından yoğunlaşıyor. Metric sonuçları Parasoft / Show View / Metrics menüsü ile görülebilir. İlginç metrikler "Coupling Between Objects" (çok fazla bağımlılık) ve "Lack of Cohesion" (sınıfın birden fazla iş yapması)
Functionally Cohesive ve Sequentially Cohesive arasındaki farkı anlatan bir yazı burada.
Analizi Başlatma
Seçim işlemi bitince "Run Tests" düğmesine tıklanır.
Example Configuration Export/Import İşlemi
Example Configuration nesnesine sağ tıklanarak kuralları Export etme imkanı var.
Statik Analiz
Eğer sadece belli bir kod parçası için statik analiz çalıştırılmak istenirse, Solution Explorer'a sağ tıklanır. Açılan menüden Parasoft/Test Using "Example Configuration" seçilir.
Analiz Sonuçları
Analiz sonuçları Show / Details altındaki Quality Tasks penceresinde kurallara göre gruplanmış olarak görülebilir.
Hiç yorum yok:
Yorum Gönder