C++的歷史與演化
C++起先是在C語言上面的一種拓展,后來演化到現在,已經是一門獨立且備受矚目的語言了。
語言關系圖: B -> C -> C++(new C -> C with class -> C++
演化路線圖: C++98 -> C++03 -> C++11 -> C++14
C++的幾種模式
C++本身被視作一個語言的聯邦,本身是一種多范型的語言。學好C++,需要了解一下的幾種C++的常用范型。
- Clean C
- Object-Oriented C++
- Template C++
- STL
C++原本的翻譯作為C plus plus, 第一版語言本身可以被稱作為C with Class。 對于Class這個名詞而言,C++有可以區分為OBP && OOP。
OBP本身是利用了C++對Data Resource的一種封裝,這里一般就是單個Class而已,很少與其他Class發生較多的交互。而OOP本身更多的使用了繼承與多態,而且OOP更加注重于Class與Class之間的關系。Class與Class之間的關系有繼承(inheritance),復合(composition)和委托(delegation)。
C++代碼的基本結構
C++的代碼一般分為聲明部分 && 實現部分。
聲明部分一般存放在.h .hpp結尾的文件中。 實現部分一般存放在.cc .cpp .C結尾的文件中。
為什么這里要區分聲明 && 實現呢。因為一個項目不可能只有一個文件,一般一個工程是多人協作式的。首先單個文件無法多人進行編輯。第二,如果每個人負責項目的一個模塊,一個只要關心自己的部分和他人與自己相關的部分了。如果實現與聲明相分離,相關的人員只需要在開發的時候約定聲明的部分,可以在開發過程中不關心實現,到最后進行代碼的集成測試就可以了。
C++的聲明文件為了防止多次包含有兩種技巧。一種是防御式聲明(ifndef), 一種使用#pragma once
- 防御式聲明
// hello.h
#ifndef HELLO_H_
#define HELLO_H_
#endif // HELLO_H_
- pragma
// hello.h
#pragma once
C++ Class
一般認為C++本身包括了C語言部分即Clean C。C語言的聲明 && 控制,C++基本與其類似。
C++的Class一般包含了構造與析構部分。構造是用來初始化一個對象,析構是對象生命周期結束后告訴編譯器如何刪除一個對象。構造函數和析構函數屬于特殊的函數。這兩種函數都是沒有返回值的。
C++的對象如果名稱叫做complex,那么構造函數就是complex(...), ...表示參數列表, 這里可以看出complex是可以有多個的,本身可以被重載。 析構函數就是~complex,析構函數是沒有參數列表的。C++如果不聲明構造函數或者析構函數的話。編譯器本身會給合成一個構造或者析構函數。合成的構造函數是沒有參數列表的。如果一個類中含有指針,最好自定義析構函數,否則合成的析構函數不會delete指針所對應的對象。
class complex {
public:
complex(int re, int im); // 構造函數
~complex(); // 析構函數
private:
int re_, im_;
};
C++本身也有權限控制比如public, private, protected。
public表示在類以外也能被訪問,而private表示只能在類中被訪問。protected表示在被繼承的類中能夠被直接訪問。class默認是private類型的,struct 默認是public類型的。這個是class/struct聲明的兩者的根本區別。
這里有一個特點如果構造函數在private區域可以被用來實現單例模式。
// singleton
#include <iostream>
using namespace std;
class Singleton {
Singleton() {}
static Singleton *instance;
public:
~Singleton() { cout << "Singleton dtor" << endl; }
struct GC {
~GC() { if(instance) { cout << "Delete Singleton" << endl; delete instance; } }
};
private:
static GC gc;
public:
static Singleton *Instance() {
if (!instance) {
instance = new Singleton;
}
return instance;
}
};
Singleton *Singleton::instance = NULL;
Singleton::GC gc;
int main()
{
Singleton *s = Singleton::Instance();
// delete t;
return 0;
}
在C++中一個member function也可以是const的,這里表示this指針是const,所以不能修改類實例的成員變量的值。const的類實例變量只能調用const 方法
class complex {
public:
complex(double r = 0, double i = 0) : re(r), im(i) {}
complex &operator+=(const complex &);
complex &operator-=(const complex &);
complex &operator*=(const complex &);
complex &operator/=(const complex &);
double real() const { return re; }
double imag() const { return im; }
private:
double re, im;
friend complex &__doapl(complex *, const complex &);
friend complex &__doami(complex *, const complex &);
friend complex &__doaml(complex *, const complex &);
};
{
const complex c(1, 2);
cout << c.real() << endl;
}
C++的函數傳值
- pass by value
通過值來傳遞給調用的函數,此時在調用的函數修改了值,原先的變量的值還是不會改變
void fun(int a)
{
a += 1;
}
{
int a = 10;
fun(a);
cout << a << endl; // 10 not 11
}
- pass by reference/pointer
通過引用來傳值,這里如果在調用的函數中修改了值,原先的值也會被修改。reference 編譯器的實現實際上是一個const pointer。
void fun(int a)
{
a += 1;
}
{
int a = 10;
fun(a);
cout << a << endl; // 11 not 10
}
Operator Overloading
C++自定義類型的一些operator是可以被重載的,比如+,+=,++,但是基本類型的是不可以的,這個會引起底層的混亂。
op any of the following 38 operators:+ - * / % ? & | ~ ! = < > += -= *= /= %= ?= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> ( ) [ ]
1) overloaded operator;
2) [user-defined conversion function](http://en.cppreference.com/w/cpp/language/cast_operator);
3) [allocation function](http://en.cppreference.com/w/cpp/memory/new/operator_new);
4) [deallocation function](http://en.cppreference.com/w/cpp/memory/new/operator_delete);
5) [user-defined literal](http://en.cppreference.com/w/cpp/language/user_literal).
Synatax
operator op (1)
operator type (2)
operator new
operator new [] (3)
operator delete
operator delete [] (4)
operator "" suffix-identifier (5) (since C++11)
in this table, @ is a placeholder representing all matching operators: all prefix operators in @a, all postfix operators other than -> in a@, all infix operators other than = in a@b
C++臨時變量
C++的臨時變量的產生一般和函數調用相關,一個調用如果沒有被一個左值接受,那么就可產生一個臨時變量,這個變量的生命周期是這條語句。這種變量在functor , 鏈式調用 和 一些使用到RAII的手法中經常會被使用到(比如Logger class)。臨時變量實際上和左值,右值有著密切的關系,以后有機會再詳細說明。
#include <iostream>
using namespace std;
class Temp {
public:
Temp(int t) : t_(t) {}
~Temp() { cout << t_ << endl; }
private:
int t_;
};
int main()
{
cout << "---------- Begin ----------" << endl;
Temp(1); // 1
Temp(2); // 2
cout << "---------- End ----------" << endl;
return 0;
}
/*
output:
---------- Begin ----------
1
2
---------- End ----------
*/
// 這里1,2在End之前被打印出來,可以看出臨時變量的聲明周期就只有單條語句
總結
在這次課程中,我對對過去的知識做了一個完整的梳理與總結。感覺還是很不錯的。以后還需要認真學習。