C++常用知識點總結
1、現在很多教材可能看到的頭檔案是:
然後用現在較新的軟體則會提示:無法打開源檔案”iostream.h”。
這是因為現在新的軟體都是采用标準 C 格式,而 iostream.h 是 VC6.0 使用的風格,也就是标準 C 格式還未出台之前的風格。
出現上述提示隻需要進行如下修改:
#include <iostream>
using namespace std;
2、在C++中main函數前面為什麼加上int,即int main?
main函數的傳回值是傳回給主調程序,使主調程序得知被調用程式的運作結果。
标準規範中規定main函數的傳回值為int,一般約定傳回0值時代表程式運作無錯誤,其它值均為錯誤号,但該約定并非強制。
如果程式的運作結果不需要傳回給主調程序,或程式開發人員确認該狀态并不重要,比如所有出錯資訊均在程式中有明确提示的情況下,可以不寫main函數的傳回值。在一些檢查不是很嚴格的編譯器中,比如VC, VS等,void類型的main是允許的。不過在一些檢查嚴格的編譯器下,比如g++, 則要求main函數的傳回值必須為int型。
是以在程式設計時,區分程式運作結果并以int型傳回,是一個良好的程式設計習慣。
3、變量的自動轉換規則
- 若參與運算量的類型不同,則先轉換成同一類型,然後進行運算。
- 轉換按資料長度增加的方向進行,以保證精度不降低。如int型和long型運算時,先把int量轉成long型後再進行運算。
- 所有的浮點運算都是以雙精度進行的,即使僅含float單精度量運算的表達式,也要先轉換成double型,再作運算。
- char型和short型參與運算時,必須先轉換成int型。
- 在指派運算中,指派号兩邊量的資料類型不同時,指派号右邊量的類型将轉換為左邊量的類型。如果右邊量的資料類型長度比左邊長時,将丢失一部分資料,這樣會降低精度
- 強制類型轉換是通過類型轉換運算來實作的。其一般形式為:(類型說明符)(表達式)其功能是把表達式的運算結果強制轉換成類型說明符所表示的類型
4、C++時間&日期表示方法
C++ 标準庫沒有提供所謂的日期類型。C++ 繼承了 C 語言用于日期和時間操作的結構和函數。為了使用日期和時間相關的函數和結構,需要在 C++ 程式中引用 頭檔案。
有四個與時間相關的類型:clock_t、time_t、size_t 和 tm。類型 clock_t、size_t 和 time_t 能夠把系統時間和日期表示為某種整數。
結構類型 tm 把日期和時間以 C 結構的形式儲存,tm 結構的定義如下:
struct tm {
int tm_sec; // 秒,正常範圍從 0 到 59,但允許至 61
int tm_min; // 分,範圍從 0 到 59
int tm_hour; // 小時,範圍從 0 到 23
int tm_mday; // 一月中的第幾天,範圍從 1 到 31
int tm_mon; // 月,範圍從 0 到 11
int tm_year; // 自 1900 年起的年數
int tm_wday; // 一周中的第幾天,範圍從 0 到 6,從星期日算起
int tm_yday; // 一年中的第幾天,範圍從 0 到 365,從 1 月 1 日算起
int tm_isdst; // 夏令時
}
下面以執行個體介紹如何擷取目前系統的時間和日期,包括本地時間和協調世界時
#include <iostream>
#include <ctime>
using namespace std;
int main( )
{
// 基于目前系統的目前日期/時間
time_t now = time();
// 把 now 轉換為字元串形式
char* dt = ctime(&now);
cout << "本地日期和時間:" << dt << endl;
// 把 now 轉換為 tm 結構
tm *gmtm = gmtime(&now);
dt = asctime(gmtm);
cout << "UTC 日期和時間:"<< dt << endl;
}
5、C++基本輸入輸出
-
該檔案定義了 cin、cout、cerr 和 clog 對象,分别對應于标準輸入流、标準輸出流、非緩沖标準錯誤流和緩沖标準錯誤流。<iostream>
-
該檔案通過所謂的參數化的流操縱器(比如 setw 和 setprecision),來聲明對執行标準化 I/O 有用的服務。<iomanip>
-
該檔案為使用者控制的檔案處理聲明服務。我們将在檔案和流的相關章節讨論它的細節。<fstream>
6、C++類通路修飾符
-
公有成員在程式中類的外部是可通路的。您可以不使用任何成員函數來設定和擷取公有變量的值public:
-
私有成員變量或函數在類的外部是不可通路的,甚至是不可檢視的。隻有類和友元函數可以通路私有成員。預設情況下,類的所有成員都是私有的private:
-
protected:
保護成員變量或函數與私有成員十分相似,但有一點不同,保護成員在派生類(即子類)中是可通路的。
特别需要注意的是,在程式設計中,要注重共有變量和私有變量的有效結合,尤其是私有變量(privated),何止防範豬隊友,更是防範六個月後的自己。
7、類的成員函數
類的成員函數的原型要寫在類體中,原型說明了函數的參數表和傳回值類型。而函數的定義一般在類外面,也可以直接在類内部定義。
前者與普通函數不同的是,實作成員函數時要指明類的名稱,具體形式為:
傳回值類型 類名 ::函數成員名(參數表){函數體};
例如:
class Line
{
public:
double length;
void setLength( double len );
double getLength( void );
};
// 成員函數定義
double Line::getLength(void)
{
return length ;
}
void Line::setLength( double len )
{
length = len;
}
更大體的表示為:
class A
{
public:
void B();
private:
int C();
protected:
bool D(int i);
};
那麼,B(),C(),D(int)都是A的成員函數
8、如何了解C++中的繼承概念?
面向對象程式設計中最重要的一個概念是繼承,簡單來說就是根據一個類定義另一個類,使得建立和維護一個應用程式更為容易。
- 假設現在需要建立一個類,那麼隻需要指定建立類繼承了一個已有類的成員即可。已有類我們稱為基類,建立類稱為派生類。
- 一個類可以派生自多個類,這意味着,它可以從多個基類繼承資料和函數。定義一個派生類,我們使用一個類派生清單來指定基類。類派生清單以一個或多個基類命名,形式如下:
其中,通路修飾符 access-specifier 是 public、protected 或 private 其中的一個,base-class 是之前定義過的某個類的名稱。如果未使用通路修飾符 access-specifier,則預設為 private。
執行個體:
// 基類
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// 派生類
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
Rect.setWidth();
Rect.setHeight();
// 輸出對象的面積
cout << "Total area: " << Rect.getArea() << endl;
return ;
}
- 派生類可以通路基類中所有的非私有成員。是以基類成員如果不想被派生類的成員函數通路,則應在基類中聲明為 private。我們可以根據通路權限總結出不同的通路類型
- 多繼承即一個子類可以有多個父類,它繼承了多個父類的特性。C++ 類可以從多個類繼承成員,文法如下:
class <派生類名>:<繼承方式1><基類名1>,<繼承方式2><基類名2>,…
{
<派生類類體>
};
8、C++檔案讀寫
要實作C++的檔案讀寫操作,需要用到标準庫
fstream
,要在 C++ 中進行檔案處理,必須在 C++ 源代碼檔案中包含頭檔案
<iostream>
和
fstream
。
- 打開檔案,格式為
void open(const char *filename, ios::openmode mode);
在這裡,open() 成員函數的第一參數指定要打開的檔案的名稱和位置,第二個參數定義檔案被打開的模式。
ios::app 追加模式。所有寫入都追加到檔案末尾。
ios::ate 檔案打開後定位到檔案末尾。
ios::in 打開檔案用于讀取。
ios::out 打開檔案用于寫入。
ios::trunc 如果該檔案已經存在,其内容将在打開檔案之前被截斷,即把檔案長度設為 0。
具體操作為:
fstream afile;
afile.open("file.dat", ios::out | ios::in );
- 關閉檔案,
void close();
- 讀取和寫入執行個體
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
char data[];
// 以寫模式打開檔案
ofstream outfile;
outfile.open("afile.dat");
cout << "Writing to the file" << endl;
cout << "Enter your name: ";
cin.getline(data, );
// 向檔案寫入使用者輸入的資料
outfile << data << endl;
cout << "Enter your age: ";
cin >> data;
cin.ignore();
// 再次向檔案寫入使用者輸入的資料
outfile << data << endl;
// 關閉打開的檔案
outfile.close();
// 以讀模式打開檔案
ifstream infile;
infile.open("afile.dat");
cout << "Reading from the file" << endl;
infile >> data;
// 在螢幕上寫入資料
cout << data << endl;
// 再次從檔案讀取資料,并顯示它
infile >> data;
cout << data << endl;
// 關閉打開的檔案
infile.close();
return ;
}
- 位置指針,
// 定位到 fileObject 的第 n 個位元組(假設是 ios::beg)
fileObject.seekg( n );
// 把檔案的讀指針從 fileObject 目前位置向後移 n 個位元組
fileObject.seekg( n, ios::cur );
// 把檔案的讀指針從 fileObject 末尾往回移 n 個位元組
fileObject.seekg( n, ios::end );
// 定位到 fileObject 的末尾
fileObject.seekg( 0, ios::end );
9、C++動态記憶體
C++記憶體分為兩部分,分别是:
- 棧:在函數内部聲明的所有變量都将占用棧記憶體。
-
堆:這是程式中未使用的記憶體,在程式運作時可用于動态配置設定記憶體。
很多時候,您無法提前預知需要多少記憶體來存儲某個定義變量中的特定資訊,所需記憶體的大小需要在運作時才能确定。在 C++ 中,您可以使用特殊的運算符為給定類型的變量在運作時配置設定堆内的記憶體,這會傳回所配置設定的空間位址。這種運算符即 new 運算符。
如果您不需要動态配置設定記憶體,可以使用 delete 運算符,删除之前由 new 運算符配置設定的記憶體。
執行個體:
#include <iostream>
using namespace std;
int main ()
{
double* pvalue = NULL; // 初始化為 null 的指針
pvalue = new double; // 為變量請求記憶體
*pvalue = ; // 在配置設定的位址存儲值
cout << "Value of pvalue : " << *pvalue << endl;
delete pvalue; // 釋放記憶體
return ;
}
數組的動态記憶體配置設定:
一維數組
// 動态配置設定,數組長度為 m
int *array=new int [m];
//釋放記憶體
delete [] array;
二維數組
int **array
// 假定數組第一維長度為 m, 第二維長度為 n
// 動态配置設定空間
array = new int *[m];
for( int i=; i<m; i++ )
{
array[i] = new int [n] ;
}
//釋放
for( int i=; i<m; i++ )
{
delete [] arrar[i];
}
delete [] array;
10、C++命名空間的概念
假設這樣一種情況,當一個班上有兩個名叫 Zara 的學生時,為了明确區分它們,我們在使用名字之外,不得不使用一些額外的資訊,比如他們的家庭住址,或者他們父母的名字等等。
同樣的情況也出現在 C++ 應用程式中。例如,您可能會寫一個名為 xyz() 的函數,在另一個可用的庫中也存在一個相同的函數 xyz()。這樣,編譯器就無法判斷您所使用的是哪一個 xyz() 函數。
是以,引入了命名空間這個概念,專門用于解決上面的問題,它可作為附加資訊來區分不同庫中相同名稱的函數、類、變量等。使用了命名空間即定義了上下文。本質上,命名空間就是定義了一個範圍。
- 命名空間的定義使用關鍵字namespace,後跟命名空間的名稱,如下所示:
namespace namespace_name{
//代碼聲明
}
為了調用帶有命名空間的函數或變量,需要在前面加上命名空間的名稱,如下所示:
name::code; // code 可以是變量或函數
執行個體:
#include <iostream>
using namespace std;
// 第一個命名空間
namespace first_space{
void func(){
cout << "Inside first_space" << endl;
}
}
// 第二個命名空間
namespace second_space{
void func(){
cout << "Inside second_space" << endl;
}
}
int main ()
{
// 調用第一個命名空間中的函數
first_space::func();
// 調用第二個命名空間中的函數
second_space::func();
return ;
}
-
using指令,您可以使用 using namespace 指令,這樣在使用命名空間時就可以不用在前面加上命名空間的名稱。這個指令會告訴編譯器,後續的代碼将使用指定的命名空間中的名稱。
執行個體:
#include <iostream>
using namespace std;
// 第一個命名空間
namespace first_space{
void func(){
cout << "Inside first_space" << endl;
}
}
// 第二個命名空間
namespace second_space{
void func(){
cout << "Inside second_space" << endl;
}
}
using namespace first_space;
int main ()
{
// 調用第一個命名空間中的函數
func();
return ;
}
11、C++多線程和程序
- 基于程序的多任務處理是程式的并發執行。
- 基于線程的多任務處理是同一程式的片段的并發執行。
- 建立程序,下面程式可以用來建立一個POSIX線程
#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)
thread 指向線程辨別符指針。
attr 一個不透明的屬性對象,可以被用來設定線程屬性。您可以指定線程屬性對象,也可以使用預設值 NULL。
start_routine 線程運作函數起始位址,一旦線程被建立就會執行。
arg 運作函數的參數。它必須通過把引用作為指針強制轉換為 void 類型進行傳遞。如果沒有傳遞參數,則使用 NULL.
- 以下簡單的執行個體代碼使用 pthread_create() 函數建立了 5 個線程,每個線程輸出”Hello Runoob!”:
#include <iostream>
// 必須的頭檔案
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
// 線程的運作函數
void* say_hello(void* args)
{
cout << "Hello Runoob!" << endl;
return ;
}
int main()
{
// 定義線程的 id 變量,多個變量使用數組
pthread_t tids[NUM_THREADS];
for(int i = ; i < NUM_THREADS; ++i)
{
//參數依次是:建立的線程id,線程參數,調用的函數,傳入的函數參數
int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
if (ret != )
{
cout << "pthread_create error: error_code=" << ret << endl;
}
}
//等各個線程退出後,程序才結束,否則程序強制結束了,線程可能還沒反應過來;
pthread_exit(NULL);
}