C++ Notlarım Aşağıda C++ ile ilgili aldığım notlar var.
C++11C++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şkenBuradaki 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 veint 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ılamazGenel 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ınamazconstructor 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 constructorBir 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() {
return Demo{ *this };
}
veya
Demo Clone() {
return {*this};
}
Copy constructor'ı etkinsizleştirmek için iki yöntem
var. İlkinde metod imzası tanımlanır ancap .cpp dosyasında metod yazılmaz.
private:
MyClass(const MyClass& that);
veya C++11 ile
MyClass(const MyClass& that) = delete;
copy Constructor ElisionBazı 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 typeC++
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.
decltypeBu 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 constructorEğ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.
templateDefault constructor'a template parametresi geçmek imkansızdır. Örnekte geçilen template sınıfa verilir.
destructorDerleyici 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_castMultiple 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 constructorDerleyicinin bir nesneyi yaratmak için kendi kendine verilen parametrenin tipini değiştirmesi engellemek demek.
Örnek:
void DoBar (Foo foo)
{
int i = foo.GetFoo ();
}
int main ()
{
DoBar (42);//Foo'nun int alan constructor metodu otomatik çağırılır
}
Aşağıdaki örnekte explicit olmayınca "conversion constructor"'ın çağrıldığı
görülebiliyor.
Çıktı olarak "Y(int)" verir.
explicit aynı zamanda conversion metodların imzasında da kullanılabilir.
Örnek:
explicit operator bool() const ;
externBir 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 referencefunction 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();
veya
void (*fp)() = &foo;
fp();
function pointerAş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 pointermember function pointer aşağıdaki gibi
çağırılır.
(d.*f)(5);
(p->*f)(5);
FunctorFunctor, 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:
LambdaLambda 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ğiauto func = [] (const string& addr) { return addr.find( ".org" ) != string::npos; }
Lambda ve ReferenceLambda 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 ConstructorYazıyı
buraya taşıdım.
Most Vexing ParseBu 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.
ÖrnekOrder of EvaluationMetoda 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'larKonuyu
C++ ve Operator başlıklı yazıya taşıdım.
OverloadingKonuyu
Overloading başlıklı yazıya taşıdım.
Overloading ve KalıtımKonuyu
Overloading başlıklı yazıya taşıdım.
POD TypeKonuyu
C++ Notlarım POD başlıklı yazıya taşıdım.
RValueRValue 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ış.
- Does it have a name ? lvalue : rvalue;
- Can I take the address of it ? lvalue : rvalue;
size_tsize_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 kelimesiBir 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 atamastruct static const olan bir struct'ın alanlarına istenirse ismen değer atanabilir.Örnek://.h file
struct mystruct {int field1;int field2};
//.cpp file
const static mystruct m = {field1 = 1, field2= 2};
primitif veya komposit tipPrimitif tipler .h dosyasında veya .cpp dosyasında ilklendirilebilir. Ancak diğer değişkenler .cpp dosyasında ilklendirilmelidir.arrayarray 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_assertDerleme 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 InterfaceTuhaf 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 FunctionVariadic 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 farkC 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 LisansLisans 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.
RulesStatic kod analizi için kullanılır. Static sekmesi seçilerek, Rules Tree sekmesinden tanımlı kurallardan işimize yarayanlar etkinleştirilir.
MetricsMetrikler 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şlatmaSeçim işlemi bitince "Run Tests" düğmesine tıklanır.
Example Configuration Export/Import İşlemiExample Configuration nesnesine sağ tıklanarak kuralları Export etme imkanı var.
Statik AnalizEğ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.