C++學習_從C到C++

1、引用的概念和應用


 1.引用的概念

下面寫法定義了一個引用,並將其初始化爲引用某個變量。
		類型名 & 引用名 = 某變量名;
		int n = 4;
		int & r = n; // r引用了n,r的類型是 int &
某個變量的引用,等價於這個變量,至關於該變量的一個別名。  

代碼示例:ios

// 課堂練習
# include <iostream>
using namespace std;

int main(void)
{
	int n = 7;
	int & r = n;
	r = 4;
	cout<<r<<" "<<n<<endl; // 輸出 4 4 
	n = 5;
	cout<<r<<" "<<n<<endl; // 輸出 5 5 
	return 0;
} 

注意點: 1. 定義引用時必定要將其初始化爲引用某個變量。
     2. 初始化之後,從一而終,不會再引用別的變量。
     3. 引用只能引用變量,不能引用常量和表達式。數組

代碼示例:函數

// 課堂練習
# include <iostream>
using namespace std;

int main(void)
{
	double a = 4, b = 5;
	double & r = a; // r引用 a 
	double & p = r; // 這時候 p 也引用了 a
	p = 10;
	cout<<a<<" "<<r<<" "<<p; // 輸出 10 10 10  
	r = b; // 這句話並不表明r從新引用b,而是把 b值賦值給r  
	cout<<a<<" "<<r<<" "<<p; // 輸出 5 5 5  
	 
	return 0;
} 

課堂習題: spa

下面程序片斷輸出結果是什麼?
	int a = 1,b = 2;
	int & r = a;
	r = b;
	r = 7;
	cout << a << endl;

2. 引用應用的簡單示例

2.1 引用做爲函數的參數指針

C語言中如何交換兩個整型變量的值?
void swap(int * a, int * b)
{
	int temp;
	temp = *a; *a=*b; *b=temp;
}
int n1, n2;
swap(&n1, &n2); // n1 n2 的值被交換
 
有了C++的引用:

void swap(int & a, int & b)
{
	int temp;
	temp = a; a=b; b=temp;
}
int n1, n2;
swap(n1, n2); // n1 n2 的值被交換

2.2 引用做爲函數的返回值  blog

// 課堂練習
# include <iostream>
using namespace std;
int n = 4;
int & SetValue()
{
	return n;
}
int main(void)
{
	SetValue() = 40; // 將40的值賦值給SetValue()函數的返回n 
	cout<<n; // 輸出40 
	return 0;
} 

2.3 常引用 內存

定義引用時,前面加const關鍵字,即爲「常引用」
int n;
const int & r = n; // r 的類型是const int &
不能經過常引用去修改其引用內容。
int n = 100;
const int & r = n;
r = 200; // 編譯錯
n = 300; // 沒問題

2.4 常引用和很是引用的轉換編譯器

const T & 和 T & 是不一樣的類型!
T &類型的引用或者T類型的變量能夠用來初始化const T &類型的引用。

而const T類型的常變量和const T &類型的引用則
不能用來初始化T &類型的引用,除非強制類型轉化。

2、const關鍵字


 0) 定義常引用 (在引用處已經講過,再也不贅述)

1) 定義常量

const int MAX_VAL = 23;
const double Pi = 3.14;
const char * SCHOOL_NAME = "PKU";

2) 定義常量指針

A) 不能經過常量指針修改其指向內容string

int n, m;
const int * p = &n; 
* p = 5; // 試圖經過指針修改指向內容, 編譯出錯
n = 4; // ok 指向的內容自己是能夠修改的
p = &m; // ok 常量指針的指向能夠發生變化

B) 不能把常量指針賦值給很是量指針,反過來能夠io

const int * p; // 常量指針
int * q; // 很是量指針
p = q; // ok
q = p; // error 企圖把常量指針賦值給很是量指針
q = (int *)p; //ok 強制類型轉化

C) 函數參數爲常量指針時,可避免函數內部不當心改變參數指針所指地方的內容

// 課堂練習
# include <iostream>
# include <string.h>
using namespace std;

void MyPrintf(const char * p)
{
	strcpy(p,"123"); // 編譯出錯 
	// 由於strcpy()函數的第一個參數是 char * 很是量指針
	// 而定義的 P 是一個常量指針,因此,賦值過程會報錯 
	printf("%s",p);  // ok
}

int main(void)
{
	char ch[5] = {"0123"};
	const char * q = ch;
	MyPrintf(q);
	return 0;
}   

課堂習題:

下面說法哪一種是對的?
A) 常引用所引用的變量,其值不能被修改
B) 不能經過常量指針,去修改其指向的變量
C) 常量指針一旦指向某個變量,就不能再指向其餘變量
D)  以上都不對

3、動態內存分配


1. 用new運算符實現動態內存分配

1.1) 用new 分配一個變量

P = new T;
T 是任意的類型名,P是類型爲T * 的指針。
動態分配出一片大小爲sizeof(T)字節的內存空間,而且將該內存空間的起始地址賦值給P。

代碼示例:

// 課堂練習
# include <iostream>
using namespace std;

int main(void)
{
	 int * p;
	 p = new int; // 給P指針分配內存
	 *p = 5;
	 cout<<*p;
	  
	return 0;
} 

課堂習題:

表達式 「new int」的返回值類型是:
A) int
B) int *
C) int &
D) void

1.2) 分配一個數組

P = new T[N];
T: 任意類型名
P: 類型爲T * 的指針
N:要分配的數組元素的個數
動態分配出一片大小爲N*sizeof(T)字節的內存空間,而且將該內存空間的起始地址賦值給P。

代碼示例:

// 課堂練習
# include <iostream>
using namespace std;

int main(void)
{
	int * p;
	p = new int[20];
	p[10] = 5;
	cout<<p[10]; // 輸出5 
	  
	return 0;
} 

1.3) new 運算符的返回值類型

new T;
new T[N];
均返回T*類型

2. 用delete運算符釋放動態分配的內存

2.1) 用new 動態分配的內存空間,必定要用delete運算符進行釋放

delete 指針; // 該指針必須指向new出來的空間
int * p = new int;
* p = 5;
delete p;
delete p; // error,不能delete兩次

代碼示例:

// 課堂練習
# include <iostream>
using namespace std;

int main(void)
{
	int * p = new int;
	*p = 5;
	cout<<*p<<endl; // 輸出5 
	delete p;
	cout<<*p<<endl; // 輸出結果不爲 5,空間已經被釋放 
	return 0;
} 

2.2) 用delete釋放動態分配的數組,要加 []

delete [] 指針; // 該指針必須指向new出來的數組
int * p = new int[20];	
p[0] = 1;
delete [] p;	

代碼示例: 

// 課堂練習
# include <iostream>
using namespace std;

int main(void)
{
	int * p = new int[20];
	p[10] = 5;
	cout<<p[10]<<endl; // 輸出5 
	printf("%p\n",p[10]); // 輸出p[10]的地址 
	delete [] p;	
	cout<<p[10]<<endl; // 輸出5,空間已經被釋放 
	printf("%p\n",p[10]); // 輸出p[10]的地址
	delete [] p; // 再次delete編譯不會報錯,可是程序沒法繼續執行	
	cout<<p[10]<<endl; // 無輸出
	printf("%p\n",p[10]); // 無輸出
	return 0;
} 

課堂習題:

下面小段程序,哪一個是正確的:
A) char * p = new int; 
		p = 'a';  
		delete p;
B) int *p = new int[25]; 
   p[10] = 100; 
   delete p;
C) char * p = new char[10];       
   p[0] = 'K'; 
   delete [] p;
D) 都不對?
		 

4、動態內存分配


1. 內聯函數 

   函數調用是有時間開銷的。
  若是函數自己只有幾條語句,執行很是快,並且函數被反覆執行不少次,相比之下調用函數所產生的這個開銷就會顯得比較大。
  爲了減小函數調用的開銷,引入了內聯函數機制。
  編譯器處理對內聯函數的調用語句時,是將整個函數的代碼插入到調用語句處,而不會產生調用函數的語句。

在函數定義前加「inline」關鍵字,便可定義內聯函數 

inline int Max(int a,int b)
{
	if( a > b) return a;
	return b;
}

2. 函數重載

一個或多個函數,名字相同,然而參數個數或參數類型不相同,這叫作函數的重載。

如下三個函數是重載關係:
int Max(double f1,double f2) { }
int Max(int n1,int n2) { }
int Max(int n1,int n2,int n3) { }

  函數重載使得函數命名變得簡單。編譯器根據調用語句的中的實參的個數和類型判斷應該調用哪一個函數。

具體使用:

(1) int Max(double f1,double f2) { }
(2) int Max(int n1,int n2) { }
(3) int Max(int n1,int n2,int n3) { }
Max(3.4,2.5);  //調用 (1)
Max(2,4);      //調用 (2)
Max(1,2,3);    //調用 (3)
Max(3,2.4);    //error,二義性

3. 函數的缺省參數

  C++中,定義函數的時候可讓最右邊的連續若干個參數有缺省值,那麼調用函數的時候,若相應位置不寫參數,參數就是缺省值。

void func( int x1, int x2 = 2, int x3 = 3){ }
func(10 ) ; //等效於 func(10,2,3)
func(10,8) ; //等效於 func(10,8,3)
func(10, , 8) ; //不行,只能最右邊的連續若干個參數缺省

函數參數可缺省的目的在於提升程序的可擴充性。

即若是某個寫好的函數要添加新的參數,而原先那些調用該函數的語句,未必須要使用新增的參數,那麼爲了不對原先那些函數調用語句的修改,就可使用缺省參數。

課堂例題:

下面說法正確的是:
A) 多個重載函數的參數個數必須不一樣。
B) 兩個函數,參數表相同,返回值類型不一樣,它們是重載關係。
C) 調用一個第二個和第三個參數都有有缺省值的函數時,能夠不寫第二個實參而寫第三個實參。
D) 使用內聯函數的目的是提升程序的運行速度。

RRR

相關文章
相關標籤/搜索