溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

C++語(yǔ)言學(xué)習(xí)(二)——C++對(duì)C語(yǔ)言基礎(chǔ)語(yǔ)法的擴(kuò)展

發(fā)布時(shí)間:2020-08-01 15:10:32 來(lái)源:網(wǎng)絡(luò) 閱讀:5025 作者:天山老妖S 欄目:編程語(yǔ)言

C++語(yǔ)言學(xué)習(xí)(二)——C++對(duì)C語(yǔ)言基礎(chǔ)語(yǔ)法的擴(kuò)展

C++是基于C語(yǔ)言擴(kuò)展發(fā)展而來(lái)的面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言,本文將主要討論C++語(yǔ)言基于C語(yǔ)言擴(kuò)展的方面。

一、實(shí)用性增強(qiáng)

C語(yǔ)言中變量的定義必須在作用域開(kāi)始的位置進(jìn)行定義。

#include <stdio.h>

int main(int argc, char *argv[])
{
    int i;//定義變量
    int j;

    //使用變量
    for(i = 0; i < 10; i++)
    {
        for(j = 0; j < 10; j++)
        {
        }
    }
    //error: 'for' loop initial declarations are only allowed in C99 mode
    for(int k = 0; k < 10; k++)
    {
    }

    return 0;
}

C++更強(qiáng)調(diào)語(yǔ)言的實(shí)用性,C++中所有的變量可以在需要使用時(shí)再定義。

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    int a = 7;
    //使用時(shí)定義變量
    for(int i = 0; i < 10; i++)
    {
        for(int j = 0; j < 10; j++)
        {
        }
    }
    return 0;
}

二、類(lèi)型增強(qiáng)

1、類(lèi)型檢查更嚴(yán)格

在C語(yǔ)言中:

const int a = 100;
int *p = &a;

在C++語(yǔ)言中:

 const int a = 100;//必須在定義的時(shí)候初始化
 const int *p = &a;//類(lèi)型必須嚴(yán)格匹配

在C++語(yǔ)言中不能隱式轉(zhuǎn)換數(shù)據(jù)類(lèi)型。
error: invalid conversion from 'const int*' to 'int*' [-fpermissive]

2、bool類(lèi)型

C語(yǔ)言中,沒(méi)有定義bool類(lèi)型,表示真用非0,假用0。
C++語(yǔ)言中,定義了自己的bool類(lèi)型,真為true,假為false,是基本類(lèi)型。
sizeof(bool) = 1
C++編譯器會(huì)將非0值轉(zhuǎn)換為true,0轉(zhuǎn)換為false

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    bool a = 0;
    printf("a = %d\n", a);//0
    bool b = -1;
    printf("b = %d\n", b);//1
    b = b + 1;//1 + 1 = 2 => 1
    printf("b = %d\n", b);//1
    printf("sizeof(bool) = %d\n", sizeof(bool));//1
    return 0;
}

3、枚舉

C語(yǔ)言中枚舉本質(zhì)就是整型,枚舉變量可以用任意整型賦值。而c++中枚舉變量,只能用被枚舉出來(lái)的元素初始化。
在C語(yǔ)言中,枚舉的使用

#include <stdio.h>
enum weekday
{
monday,tuesday,wednesday,thursday,friday,saturday,sunday
};
int main(int argc, char **argv)
{
    enum weekday day = monday;
    enum weekday a = sunday;
    enum weekday b = 100;
//weekday c = sunday;錯(cuò)誤用法,需要使用enum聲明
    printf("%d %d %d\n", day, a, b); 
    return 0;
}

在C++語(yǔ)言中枚舉的使用

enum weekday
{
    monday,tuesday,wednesday,thursday,friday,saturday,sunday
};
int main()
{
    weekday day = sunday;
    enum weekday a = monday;
    cout<<day<<" "<<a<<endl;
    return 0;
}

4、表達(dá)式做左值

C語(yǔ)言中表達(dá)式不可以做左值,C++中某些表達(dá)式可以做左值。
(a = b) = 6;

5、register關(guān)鍵字

register關(guān)鍵字請(qǐng)求編譯器將局部變量存儲(chǔ)到寄存器中。
C語(yǔ)言中,無(wú)法獲取register關(guān)鍵字修飾的局部變量的地址。
C++語(yǔ)言中,C++依然支持register關(guān)鍵字,但C++編譯器對(duì)register關(guān)鍵字進(jìn)行了優(yōu)化,C++語(yǔ)言中可以獲取register變量的地址。對(duì)于早期的C++編譯器,C++編譯器發(fā)現(xiàn)程序中需要獲取register關(guān)鍵字修飾的變量地址時(shí),register關(guān)鍵字對(duì)變量的聲明失效;對(duì)于現(xiàn)代C++編譯器,register關(guān)鍵字的存在只是為了兼容C語(yǔ)言,register關(guān)鍵字本身已經(jīng)無(wú)任何意義。

6、全局變量

C語(yǔ)言中可以重復(fù)定義多個(gè)重名的全局變量,同名的全局變量被鏈接到全局?jǐn)?shù)據(jù)區(qū)的一個(gè)地址空間。

#include <stdio.h>

//定義重名的全局變量合法
int a;
int a;

int main(int argc, char *argv[])
{

    return 0;
}

C++語(yǔ)言不允許定義多個(gè)同名的全局變量。

#include <iostream>

using namespace std;

//定義重名的全局變量是非法的
int a;
int a;
//error: redefinition of 'int a'

int main(int argc, char *argv[])
{

    return 0;
}

7、struct

C語(yǔ)言中,struct定義了一種變量的集合,struct定義的標(biāo)識(shí)符不是一種新類(lèi)型。C語(yǔ)言中的struct內(nèi)部不可以定義函數(shù)。

#include <stdio.h>

struct tag_student
{
    const char* name;
    int age;
};
typedef struct tag_student Student;

int main(int argc, char *argv[])
{
    //合法定義
    Student s;
    s.name = "lee";
    s.age = 30;
    //非法定義
    tag_student ts;//error: unknown type name 'tag_student'
    //合法定義
    struct tag_student sts;
    sts.name = "bauer";
    sts.age = 23;
    return 0;
}

C語(yǔ)言中只有使用typedef關(guān)鍵字重命名struct后才可以使用Student定義變量。
C++語(yǔ)言中struct用于定義一種全新的類(lèi)型,可以使用struct定義的標(biāo)識(shí)符直接定義變量。

#include <iostream>

using namespace std;

struct Student
{
    const char* name;
    int age;
};

int main(int argc, char *argv[])
{
    Student s;
    s.name = "bauer";
    s.age = 20;
    return 0;
}

8、函數(shù)參數(shù)

在C語(yǔ)言中,函數(shù)在定義時(shí)沒(méi)有給出參數(shù)、返回值的類(lèi)型,默認(rèn)為int。
int f()表示返回值為int,接受任意參數(shù)的函數(shù)
f(void)表示返回值為int的無(wú)參數(shù)函數(shù)

#include <stdio.h>

//接受任意個(gè)參數(shù),返回int類(lèi)型
func1()
{
    return 30;
}
//無(wú)參函數(shù),返回int類(lèi)型
func2(void)
{
    return 20;
}
//參數(shù)i默認(rèn)為int類(lèi)型
void func3(i)
{
    printf("i = %d\n", i);
}

int main(int argc, char *argv[])
{
    int a = func1(1,2,3);
    printf("a = %d\n", a);//30
    int b = func2();
    printf("b = %d\n", b);//20
    func3(10);//10
    return 0;
}

C++語(yǔ)言中,所有的標(biāo)識(shí)符都必須顯示的聲明類(lèi)型。C語(yǔ)言中的默認(rèn)類(lèi)型在C++中是不合法的。

#include <iostream>

using namespace std;

//error: ISO C++ forbids declaration of 'func1' with no type [-fpermissive]
func1()
{
    return 30;
}
//無(wú)參數(shù),返回int
int func2()
{
    return 20;
}

int func3(void)
{
    return 10;
}

int main(int argc, char *argv[])
{
    //error: too many arguments to function 'int func2()'
    int a = func2(20);
    int b = func2();
    int c = func3();
    return 0;
}

9、const

C語(yǔ)言中,const修飾的變量是只讀的,本質(zhì)還是變量,可以借助指針修改變量空間的值;const修飾的變量會(huì)分配存儲(chǔ)空間,const修飾的局部變量分配在棧上,const修飾的全局變量分配在只讀存儲(chǔ)區(qū),修改const修飾的全局變量的值將會(huì)導(dǎo)致異常錯(cuò)誤;const只在編譯期有效,在運(yùn)行期無(wú)效;const關(guān)鍵詞用于向編譯器表明const修飾的變量不能做左值。

#include <stdio.h>

//const全局變量,分配在只讀存儲(chǔ)區(qū)
const int number = 10;

int main(int argc, char *argv[])
{
    const int c = 0;
    int* p = (int*)&c;//編譯器會(huì)為c分配空間
    printf("Begin...\n");
    *p = 5;
    printf("c = %d\n", c);//5
    c = 10;//error: assignment of read-only variable 'c'
    int* cp = &number;
    *cp = 100;//程序異常
    const int number = 10;
    int array[number] = {0};//只讀變量,編譯時(shí)無(wú)法確定其值
    //error: variable-sized object may not be initialized
    printf("End...\n");
    return 0;
}

C++語(yǔ)言中,對(duì)C語(yǔ)言基礎(chǔ)的const進(jìn)行了優(yōu)化處理。編譯器編譯過(guò)程中遇到const修飾的標(biāo)識(shí)符時(shí),會(huì)將const修飾的標(biāo)識(shí)符放入符號(hào)表中。如果后續(xù)編譯過(guò)程中發(fā)現(xiàn)const修飾的標(biāo)識(shí)符時(shí),直接使用符號(hào)表中const修飾的標(biāo)識(shí)符對(duì)應(yīng)的值直接替換。但在以下情況下C++編譯器會(huì)給const聲明的常量分配空間:
A、const修飾的常量為全局(extern修飾),并且需要在其它文件中使用
B、使用&操作符對(duì)cosnt常量取地址
C++編譯器雖然會(huì)對(duì)const常量分配空間,但不會(huì)使用其存儲(chǔ)空間的值。
const常量的判別:
A、只有用字面量初始化的const常量才會(huì)進(jìn)入符號(hào)表
B、使用其他變量初始化的const常量仍然是只讀變量
C、被volatile修飾的const常量不會(huì)進(jìn)入符號(hào)表
const引用類(lèi)型與初始化變量的類(lèi)型相同時(shí),初始化變量為只讀變量;不同時(shí),生成一個(gè)新的只讀變量。

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    const int a = 10;
    //error: invalid conversion from 'const int*' to 'int*'
    int* p = &a;
    int* cp = (int*)&a;
    *cp = 100;
    printf("a = %d\n", a);//10
    printf("*cp = %d\n", *cp);//100

    int b = 3;
    //使用其它變量初始化的const常量是只讀變量
    const int c = b;
    //error: variable-sized object 'array' may not be initialized
    int array[c] = {0};
    //使用volatile修飾的const常量不會(huì)進(jìn)入符號(hào)表
    volatile const int d = 10;
    //error: variable-sized object 'varray' may not be initialized
    int varray[d] = {0};

    return 0;
}

C++語(yǔ)言中const與宏定義的不同在于,const常量由編譯器處理,編譯器會(huì)對(duì)const常量進(jìn)行類(lèi)型檢查和作用域檢查,而宏定義由預(yù)處理器進(jìn)行處理,是單純的文本替換。

#include <iostream>

using namespace std;

void func1()
{
    #define NUMBER 100
    const int number = 10;
    printf("NUMBER = %d\n",NUMBER);
    printf("number = %d\n",number);
}

void func2()
{
    //宏定義沒(méi)有作用域概念,預(yù)處理時(shí)直接替換
    printf("NUMBER = %d\n",NUMBER);
    printf("number = %d\n",number);
    //'number' was not declared in this scope
}

int main(int argc, char *argv[])
{
    func1();
    func2();
    const int number = 10;
    //編譯時(shí)使用符號(hào)表的值替換
    int array[number] = {0};
    return 0;
}

10、三目運(yùn)算符

C語(yǔ)言中,三目運(yùn)算符返回變量的值,三目運(yùn)算符表達(dá)式不能做左值使用。
C++語(yǔ)言中,三目運(yùn)算符可直接返回變量本身,三目運(yùn)算符表達(dá)式可以作為左值使用。但是當(dāng)三目運(yùn)算符表達(dá)式可能返回的值中有一個(gè)是常量值,則三目運(yùn)算符表達(dá)式不能作為左值使用。
C++中,當(dāng)三目運(yùn)算符表達(dá)式可能返回的都是變量時(shí),返回的是變量的引用;當(dāng)三目運(yùn)算符表達(dá)式可能返回的有常量值時(shí),返回的是值。

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    int a = 3;
    int b = 2;
    //返回變量本身,可以做左值
    (a>b?a:b) = 10;
    printf("a>b?a:b = %d\n",a>b?a:b);
    //返回變量的值,不能做左值
    (a<b?1:b) = 20;
    //error: lvalue required as left operand of assignment
    return 0;
}

三、輸入與輸出

1、cin&cout

cin和cout是C++的標(biāo)準(zhǔn)輸入流和輸出流,在頭文件 iostream 中定義。
流名 含義 隱含設(shè)備 流名 含義 隱含設(shè)備
cin 標(biāo)準(zhǔn)輸入 鍵盤(pán) cerr 標(biāo)準(zhǔn)錯(cuò)誤輸出 屏幕
cout 標(biāo)準(zhǔn)輸出 屏幕 clog cerr 的緩沖輸出 屏幕

int main()
{
    char name[30];
    int age;
    cout<<"pls input name and age:"<<endl;
    cin>>name;
    cin>>age;
    cout<<"your name is: "<<name<<endl;
    cout<<"your age is: "<<age<<endl;
    return 0;
}

2、格式化

A、按進(jìn)制輸出數(shù)據(jù)類(lèi)型

cout<<dec<<i<<endl;
cout<<hex<<i<<endl;
cout<<oct<<i<<endl;

B、設(shè)置域?qū)?,設(shè)置左右對(duì)齊及填充字符

int main()
{
    cout<<setw(10)<<1234<<endl;
    cout<<setw(10)<<setfill('0')<<1234<<endl;
    cout<<setw(10)<<setfill('0')<<setiosflags(ios::left)<<1234<<endl;
    cout<<setw(10)<<setfill('-')<<setiosflags(ios::right)<<1234<<endl;
    return 0;
}

C、實(shí)型數(shù)據(jù)的設(shè)置

cout<<setw(5)<<'a'<<endl<<setw(5)<<100<<endl
        <<setprecision(2)<<setiosflags(ios::fixed)<<120.00<<endl;

四、函數(shù)重載

1、函數(shù)重載簡(jiǎn)介

C語(yǔ)言中不允許重名函數(shù)的存在。
C++語(yǔ)言中為了簡(jiǎn)化編程允許重名函數(shù)的存在,即使用同一個(gè)函數(shù)名定義不同的函數(shù),重名函數(shù)稱(chēng)為函數(shù)重載。
重載函數(shù)本質(zhì)是定義的相互獨(dú)立的不同函數(shù)。當(dāng)函數(shù)名和不同的參數(shù)搭配時(shí)函數(shù)的含義不同。

int abs(int a)
{
    return a>0? a:-a;
}
double abs(double a)
{
    return a>0? a:-a;
}

2、函數(shù)重載規(guī)則

函數(shù)重載的規(guī)則如下:
A、函數(shù)名相同。
B、參數(shù)個(gè)數(shù)不同,參數(shù)的類(lèi)型不同,參數(shù)順序不同,均可構(gòu)成重載。
C、返回值類(lèi)型不同則不可以構(gòu)成重載。

#include <iostream>

using namespace std;

int func(int a, int b, int c = 0)
{
    return a + b + c;
}

int func(int a, int b)
{
    return a + b;
}

int main(int argc, char *argv[])
{
    //函數(shù)調(diào)用時(shí)出現(xiàn)二義性
    int x = func(1,2);
    //error: call of overloaded 'func(int, int)' is ambiguous
    return 0;
}

3、函數(shù)重載的匹配規(guī)則

編譯器調(diào)用重載函數(shù)的匹配規(guī)則如下:
A、將所有同名函數(shù)作為候選者
B、尋找可行的候選參數(shù)
C、匹配成功或失敗
函數(shù)重載的匹配規(guī)則如下:
A、精確匹配實(shí)參,找到則調(diào)用。
B、通過(guò)默認(rèn)參數(shù)能夠匹配實(shí)參
C、通過(guò)默認(rèn)類(lèi)型轉(zhuǎn)換匹配實(shí)參
通過(guò)默認(rèn)類(lèi)型轉(zhuǎn)換匹配實(shí)參時(shí),通過(guò)隱式轉(zhuǎn)換尋求一個(gè)匹配,找到則調(diào)用。
C++允許int到long和double的隱式類(lèi)型轉(zhuǎn)換,因此在函數(shù)重載時(shí)會(huì)引起二義性,解決方法是在調(diào)用時(shí)強(qiáng)轉(zhuǎn)類(lèi)型。

#include <iostream>

using namespace std;

int func(int a, int b)
{
    return a + b;
}

double func(double a, double b,double c)
{
    cout << "func(double a, double b,double c)"<<endl;
    return a + b + c;
}

long func(long a, long b,long c)
{
    cout << "func(long a, long b,long c)"<<endl;
    return a + b + c;
}

int main(int argc, char *argv[])
{
    int a = 1;
    int b = 2;
    int c = 3;
    //int xa = func(a,b,c);//出現(xiàn)二義性
    int x = func((long)a,(long)b,(long)c);
    printf("x = %d\n", x);

    return 0;
}

編譯器調(diào)用重載函數(shù)匹配失敗的規(guī)則:
A、如果最終找到的候選函數(shù)不唯一,則出現(xiàn)二義性,編譯報(bào)錯(cuò)。
B、如果無(wú)法匹配所有候選者,函數(shù)未定義,編譯報(bào)錯(cuò)。
重載函數(shù)使用默認(rèn)參數(shù)可能會(huì)造成二義性。

#include <iostream>

using namespace std;

int func(int a, int b, int c = 0)
{
    return a + b + c;
}

int func(int a, int b)
{
    return a + b;
}

int main(int argc, char *argv[])
{
    //函數(shù)調(diào)用時(shí)出現(xiàn)二義性
    int x = func(1,2);
    //error: call of overloaded 'func(int, int)' is ambiguous
    return 0;
}

4、函數(shù)重載的底層實(shí)現(xiàn)

C++利用name mangling(傾軋)技術(shù),來(lái)改名函數(shù)名,區(qū)分參數(shù)不同的同名函數(shù)。
C++的name mangling實(shí)現(xiàn)使用 v c i f l d表示void char int float long double及其引用。

    void func(char a); // func_c(char a)
    void func(char a, int b, double c);//func_cid(char a, int b, double c);

name mangling發(fā)生在兩個(gè)階段,.cpp編譯階段和.h的聲明階段。只有兩個(gè)階段同時(shí)進(jìn)行,才能匹配調(diào)用。

#include <iostream>

using namespace std;
//函數(shù)類(lèi)型:int(int,int)
int func(int a, int b)
{
    return a + b;
}
//函數(shù)類(lèi)型:double(double, double, double)
double func(double a, double b,double c)
{
    cout << "func(double a, double b,double c)"<<endl;
    return a + b + c;
}
//函數(shù)類(lèi)型:long(long,long,long)
long func(long a, long b,long c)
{
    cout << "func(long a, long b,long c)"<<endl;
    return a + b + c;
}

int main(int argc, char *argv[])
{
    int a = 1;
    int b = 2;
    int c = 3;
    //int func(int a, int b)
    printf("x1 = 0x%X\n", (int(*)(int,int))func);
    //long func(long a, long b,long c)
    printf("x2 = 0x%X\n", (long(*)(long,long,long))func);
    //double func(double a, double b,double c)
    printf("x3 = 0x%X\n", (double(*)(double,double,double))func);

    return 0;
}

使用nm工具查看main.o文件中符號(hào)表信息的命令如下:
nm.exe -a main.o
func重載函數(shù)的符號(hào)表信息如下:

00000036 T __Z4funcddd
00000029 T __Z4funcii
00000090 T __Z4funclll

上述的信息表示代碼中的三個(gè)重載函數(shù)。

5、函數(shù)重載與函數(shù)指針

將重載函數(shù)名賦值給函數(shù)指針時(shí),根據(jù)重載規(guī)則選擇與函數(shù)指針參數(shù)列表一致的函數(shù)。重載函數(shù)的函數(shù)類(lèi)型與函數(shù)指針類(lèi)型必須嚴(yán)格匹配(不能有任何類(lèi)型的隱式轉(zhuǎn)換),此時(shí)函數(shù)返回類(lèi)型將參與函數(shù)類(lèi)型匹配。
函數(shù)重載必須發(fā)生在同一個(gè)作用域,無(wú)法通過(guò)函數(shù)名得到重載函數(shù)的入口地址。
重載函數(shù)的函數(shù)類(lèi)型不同。

#include <iostream>

using namespace std;
//函數(shù)類(lèi)型:int(int,int)
typedef int(*pFunc1)(int,int);
int func(int a, int b)
{
    cout << "func(int a, int b)"<<endl;
    return a + b;
}
//函數(shù)類(lèi)型:double(double, double, double)
typedef double(*pFunc2)(double,double,double);
double func(double a, double b,double c)
{
    cout << "func(double a, double b,double c)"<<endl;
    return a + b + c;
}
//函數(shù)類(lèi)型:long(long,long,long)
typedef long(*pFunc3)(long,long,long);
long func(long a, long b,long c)
{
    cout << "func(long a, long b,long c)"<<endl;
    return a + b + c;
}

int main(int argc, char *argv[])
{
    int a = 1;
    int b = 2;
    int c = 3;
    pFunc1 func1 = func;
    int x1 = func1(1,2);//int func(int a, int b)
    printf("func1 = %d\n", x1);
    pFunc2 func2 = func;
    int x2 = func2(1,2,3);//double func(double a, double b,double c)
    printf("func2 = %d\n", x2);
    pFunc3 func3 = func;
    int x3 = func3(1,2,3);//long func(long a, long b,long c)
    printf("func3 = %d\n", x3);

    return 0;
}

重載函數(shù)的調(diào)用可能會(huì)存在隱式類(lèi)型轉(zhuǎn)換,比如int到long、double類(lèi)型的轉(zhuǎn)換,但是要函數(shù)指針調(diào)用重載函數(shù)時(shí),函數(shù)指針的類(lèi)型必須與重載函數(shù)的類(lèi)型嚴(yán)格匹配。

6、函數(shù)重載的注意事項(xiàng)

函數(shù)重載的注意事項(xiàng)如下:
A、函數(shù)重載必然發(fā)生在同一個(gè)作用域中。
B、編譯器需要使用參數(shù)列表或函數(shù)類(lèi)型進(jìn)行函數(shù)的選擇。
C、不能直接通過(guò)函數(shù)名得到重載函數(shù)的入口地址。

五、C++與C的相互調(diào)用

1、C++與C的兼容

C++完全兼容C語(yǔ)言,因此必須完全兼容C的類(lèi)庫(kù)。由于.c文件的類(lèi)庫(kù)文件中函數(shù)名并沒(méi)有發(fā)生name manling行為,而在包含.c文件所對(duì)應(yīng)的.h文件時(shí),.h 文件要發(fā)生name manling行為,因而會(huì)在編譯鏈接時(shí)候發(fā)生錯(cuò)誤。
C++為了避免上述錯(cuò)誤的發(fā)生,重載了關(guān)鍵字extern。只需要要避免name manling的函數(shù)前,加extern "C"如有多個(gè),則extern "C"{}。
C語(yǔ)言標(biāo)準(zhǔn)庫(kù)中實(shí)際上對(duì)C++語(yǔ)言程序引用時(shí)做了特殊處理,在C++語(yǔ)言編譯器編譯時(shí)使用extern "C"將C語(yǔ)言的標(biāo)準(zhǔn)庫(kù)函數(shù)排除了命名傾軋。
為了確保無(wú)論在C、C++編譯器中C代碼以C語(yǔ)言方式編譯:

#ifdef __cplusplus
extern "C"{
#endif
//c-style code
#ifdef __cplusplus
}
#endif

C++編譯器不能以C語(yǔ)言方式編譯重載函數(shù),C++編譯器將函數(shù)名和參數(shù)列表編譯為目標(biāo)名,C語(yǔ)言編譯方式只將函數(shù)名作為目標(biāo)名進(jìn)行編譯。

2、C++代碼引用C函數(shù)

C++調(diào)用C語(yǔ)言編碼的.dll時(shí),當(dāng)包含.dll的頭文件或聲明接口函數(shù)時(shí)需要加extern “C”。
add.h源碼:

#ifndef ADD_H
#define ADD_H

extern int add(int a, int b);

#endif

add.c源碼:

#include "add.h"

int add(int a, int b)
{
    return a + b;
}

main.cpp源碼:

#include <stdio.h>

extern "C"
{
#include "add.h"
}
int main()
{
    int c = add(10, 100);
    printf("%d\n", c);
    return 0;
}
gcc add.c -o add.o
g++ add.o main.cpp

3、C代碼引用C++函數(shù)

C代碼中引用C++的函數(shù)和變量時(shí),C++頭文件需要添加extern “C”,但在C代碼中不能直接引用聲明了extern “C”的C++頭文件,C代碼中只需要將C++中定義的extern “C”函數(shù)聲明為extern類(lèi)型即可。
add.h源碼:

#ifndef ADD_H
#define ADD_H

extern "C" int add(int a, int b);

#endif

add.cpp源碼:

#include "add.h"

int add(int a, int b)
{
    return a + b;
}

main.c源碼:

#include <stdio.h>
//#include "add.h"   錯(cuò)誤
extern int add(int a, int b);

int main()
{
    int x = add(1, 2);
    printf("x = %d\n", x);
    return 0;
}

編譯:

g++ -c add.cpp -o add.o
 gcc main.c add.o -lstdc++

或是gcc add.cpp main.c -lstdc++
g++會(huì)自動(dòng)進(jìn)行C++標(biāo)準(zhǔn)庫(kù)的連接;用gcc連接C++程序也可以,但需要人為指定連接C++標(biāo)準(zhǔn)庫(kù)(-lstdc++),否則就會(huì)出現(xiàn)undefined reference to __gxx_personality_v/0之類(lèi)的錯(cuò)誤。

六、操作符重載

C++提供了運(yùn)算符重載機(jī)制。可以為自定義數(shù)據(jù)類(lèi)型重載運(yùn)算符。實(shí)現(xiàn)構(gòu)造數(shù)據(jù)類(lèi)型也可以像基本數(shù)據(jù)類(lèi)型一樣的運(yùn)算特性。

struct COMP
{
    float real;
    float image;
};
COMP operator+(COMP one, COMP another)
{
    one.real += another.real;
    one.image += another.image;
    return one;
}
int main()
{
    COMP c1 = {1,2};
    COMP c2 = {3,4};
    COMP sum = operator+(c1,c2); //c1+c2;
    cout<<sum.real<<" "<<sum.image<<endl;
    return 0;
}

實(shí)例代碼重載了一個(gè)全局的操作符+號(hào)用于實(shí)現(xiàn)將兩個(gè)自定義結(jié)構(gòu)體類(lèi)型相加。本質(zhì)是函數(shù)的調(diào)用。

七、函數(shù)默認(rèn)參數(shù)

1、函數(shù)參數(shù)默認(rèn)值

C++語(yǔ)言中,可以在函數(shù)聲明時(shí)為參數(shù)提供一個(gè)默認(rèn)值。當(dāng)函數(shù)調(diào)用沒(méi)有提供參數(shù)的值時(shí),使用默認(rèn)值。

2、默認(rèn)參數(shù)的規(guī)則

函數(shù)默認(rèn)參數(shù)的規(guī)則如下:
A、默認(rèn)參數(shù)的順序,是從右向左,不能跳躍。
B、定義在前,調(diào)用在后(此時(shí)定義和聲明為一體),默認(rèn)參數(shù)在定義處;聲明在前,調(diào)用在后,默認(rèn)參數(shù)在聲明處。
C、一個(gè)函數(shù),不能既作重載,又作默認(rèn)參數(shù)的函數(shù)。當(dāng)你少寫(xiě)一個(gè)參數(shù)時(shí),系統(tǒng)無(wú)法確認(rèn)是重載還是默認(rèn)參數(shù)。
函數(shù)調(diào)用時(shí)參數(shù)從左到右匹配,如果一個(gè)參數(shù)使用了默認(rèn)值,則后續(xù)參數(shù)必須使用默認(rèn)值。

3、使用示例

A、單個(gè)參數(shù)

#include <iostream>
#include <time.h>

using namespace std;

void weatherForcast(char * w="sunny")
{
    time_t t = time(0);
    char tmp[64];
    strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A ",localtime(&t) );
    cout<<tmp<< "today is weahter "<<w<<endl;
}

int main(int argc, char *argv[])
{
    //sunny windy cloudy foggy rainy
    weatherForcast();
    weatherForcast("rainny");
    weatherForcast();
    return 0;
}

B、多個(gè)參數(shù)

#include <iostream>

using namespace std;

float volume(float length, float weight = 4,float high = 5)
{
    return length*weight*high;
}

int main(int argc, char *argv[])
{
    float v = volume(10);
    float v1 = volume(10,20);
    float v2 = volume(10,20,30);
    cout<<v<<endl;
    cout<<v1<<endl;
    cout<<v2<<endl;
    return 0;
}

4、函數(shù)占位參數(shù)

C++語(yǔ)言中可以為函數(shù)提供占位參數(shù),占位參數(shù)只有類(lèi)型聲明,沒(méi)有參數(shù)名聲明。由于C++類(lèi)型檢查較為嚴(yán)格,為兼容C語(yǔ)言,可以將函數(shù)參數(shù)默認(rèn)值和占位參數(shù)結(jié)合使用。
C語(yǔ)言中func函數(shù)如下:

#include <stdio.h>

void func()
{

}

int main(int argc, char *argv[])
{
    func(5,10);
    return 0;
}

C語(yǔ)言中func函數(shù)接收任意個(gè)數(shù)的參數(shù)。
C++語(yǔ)言中對(duì)func函數(shù)增加占位參數(shù)可以使C語(yǔ)言中的func函數(shù)快速地滿(mǎn)足C++語(yǔ)言的語(yǔ)法要求,代碼如下:

#include <iostream>

using namespace std;

void func(int x, int = 0)
{

}

int main(int argc, char *argv[])
{
    func(5,10);
    return 0;
}

八、引用

1、引用簡(jiǎn)介

變量名,本身是一段內(nèi)存的引用,即別名(alias)。引用,是為己有變量起一個(gè)別名。
Type& name = var;

     int a;
     int &b = a;

普通引用在定義時(shí)必須使用同類(lèi)型的變量進(jìn)行初始化。

2、引用的規(guī)則

A、引用沒(méi)有定義,是一種關(guān)系型聲明。聲明它和原有某一變量(實(shí)體)的關(guān)系。故 而類(lèi)型與原類(lèi)型保持一致,且不分配內(nèi)存,與被引用的變量有相同的地址。
B、聲明的時(shí)候必須初始化,一經(jīng)聲明,不可變更。
C、可對(duì)引用再次引用。多次引用的結(jié)果,是某一變量具有多個(gè)別名。
D、&符號(hào)前有數(shù)據(jù)類(lèi)型時(shí),是引用。其它皆為取地址。

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    int a = 3;
    int c = 6;
    float f = 3.14;
    int& b = a;
    printf("&a = 0x%X\n", &a);
    printf("&b = 0x%X\n", &b);
    //error: redeclaration of 'int& b'
    int& b = c;//error
    //給b賦值
    b = c;
    //引用的類(lèi)型必須與變量類(lèi)型相同
    int& d = f;//error
    //error: invalid initialization of reference of type 'int&' from expression of type 'float'

    //引用在定義時(shí)必須初始化
    int& rd;//error
    //error: 'rd' declared as reference but not initialized
    //引用不可以使用字面值初始化
    int& r = 10;//error
    //error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
    return 0;
}

3、引用的應(yīng)用

函數(shù)中的引用形參不需要進(jìn)行初始化,函數(shù)調(diào)用時(shí)進(jìn)行初始化。

#include <iostream>

using namespace std;
//引用
void swap(int &a, int &b)
{
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
    printf("swap(int &a, int &b)\n");
}
//指針
void swap(int* a, int* b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
    printf("swap(int* a, int* b)\n");
}

int main(int argc, char *argv[])
{
    int a = 3;
    int b = 6;
    swap(a,b);
    printf("a = %d\n",a);//6
    printf("b = %d\n",b);//3
    swap(&a,&b);
    printf("a = %d\n",a);//3
    printf("b = %d\n",b);//6
    return 0;
}

4、引用的提高
A、可以定義指針的引用,但不能定義引用的引用。

  int a;
    int* p = &a;
    int*& rp = p; // ok
    int& r = a;
    int&& rr = r; // error

B、可以定義指針的指針(二級(jí)指針),但不能定義引用的指針。

  int a;
    int* p = &a;
    int** pp = &p; // ok
    int& r = a;
    int&* pr = &r; // error

C、可以定義指針數(shù)組,但不能定義引用數(shù)組,可以定義數(shù)組引用。

  int a, b, c;
    int* parr[] = {&a, &b, &c}; // ok
    int& rarr[] = {a, b, c}; // error
    int arr[] = {1, 2, 3};
    int (&rarr)[3] = arr; // ok 的

數(shù)組是連續(xù)的存儲(chǔ)空間,數(shù)組中的元素如果是引用,會(huì)導(dǎo)致數(shù)組的元素存儲(chǔ)不連續(xù)。引用數(shù)組會(huì)破壞數(shù)組存儲(chǔ)空間的連續(xù)性。

5、const引用

const引用所引用的對(duì)象必須是const的,將普通引用綁定到const引用對(duì)象是不合法的。
const type& name = var;
const引用可使用相關(guān)類(lèi)型的對(duì)象(常量,非同類(lèi)型的變量或表達(dá)式)初始化,const引用讓變量具有只讀屬性,是const引用與普通引用最大的區(qū)別。
非const引用只能綁定到與該引用同類(lèi)型的對(duì)象。
當(dāng)const引用使用字面常量值初始化時(shí),C++編譯器會(huì)為常量值分配空間,使用字面常量對(duì)const引用初始化將生成一個(gè)只讀變量。

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    int a = 10;
    const int& ra = a;//const引用,為只讀變量
    //只讀變量不能作為左值
    ra = 100;//error: assignment of read-only reference 'c'
    int* p = (int*)&ra;
    *p = 5;
    printf("ra = %d\n", ra);//5
    const int& rb = 10;//rb為只讀變量,占用內(nèi)存空間
    //只讀變量不能作為左值
    rb = 100;//error
    int arraya[ra] = {0};//error
    //error: variable-sized object 'arraya' may not be initialized
    int arrayb[rb] = {0};//error
    //error: variable-sized object 'arrayb' may not be initialized
    double pi = 3.14;
    int& rpi = pi;//非法
    //error: invalid initialization of reference of type 'int&' from expression of type 'double'
    const int& crpi = pi;//合法
    printf("rpi= %d\n",crpi);//3
    return 0;
}

6、引用的本質(zhì)

C++編譯器在編譯過(guò)程中使用指針常量作為引用的內(nèi)部實(shí)現(xiàn),因此引用所占用空間大小與指針相同。引用的本質(zhì)是一個(gè)指針常量。
type & name&lt;====&gt; type * const name;
使用引用時(shí)不能返回局部變量的引用

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    printf("sizeof(char&) = %d\n", sizeof(char&));//1
    char c = 'a';
    char& rc = c;
    printf("sizeof(char&) = %d\n", sizeof(rc));//1
    return 0;
}

上述代碼的匯編代碼如下:
C++語(yǔ)言學(xué)習(xí)(二)——C++對(duì)C語(yǔ)言基礎(chǔ)語(yǔ)法的擴(kuò)展
將字符’a’(0x61)存儲(chǔ)到指針寄存器0x1b,將0x1b放入eax數(shù)據(jù)寄存器中,再將eax數(shù)據(jù)寄存器存儲(chǔ)內(nèi)容放入指針寄存器0x1c中。

九、new/delete

C語(yǔ)言中提供了malloc和free兩個(gè)系統(tǒng)函數(shù),完成對(duì)堆內(nèi)存的申請(qǐng)和釋放。而C++則提供了兩關(guān)鍵字new和delete。

1、new

new分配內(nèi)存空間時(shí),不能保證按需分配,分配內(nèi)存空間大小可能會(huì)大于所需空間大小。因此,new會(huì)分配至少申請(qǐng)大小的內(nèi)存空間。
A、開(kāi)辟單變量地址空間

  int *p = new int; //開(kāi)辟大小至少為sizeof(int)空間
    int *a = new int(5); //開(kāi)辟大小至少為sizeof(int)空間,并初始化為 5

B、開(kāi)辟數(shù)組空間
一維: int a = new int[100];//開(kāi)辟一個(gè)大小不少于400字節(jié)的整型數(shù)組空間
二維: int (
a)[6] = new int[5][6]
三維: int (*a)[5][6] = new int[3][5][6]

2、delete

A、釋放單變量空間

int *a = new int;
delete a; //釋放單個(gè) int 的空間

B、釋放數(shù)組空間

int *a = new int[5];
delete []a; //釋放 int 數(shù)組空間

3、new/delete應(yīng)用

  int *p = new int(5);
    cout<<*p<<endl;
    delete p;

    char *pp = new char[10];
    strcpy(pp,"china");
    cout<<pp<<endl;
    delete []pp;

  string *ps = new string("china");
    cout<<*ps<<endl; //cout<<ps<<endl;
    delete ps;

  char **pa= new char*[5];
    memset(pa,0,sizeof(char*[5]));
    pa[0] = "china";
    pa[1] = "america";
    char **pt = pa;
    while(*pt)
    {
        cout<<*pt++<<endl;
    }
    delete []pt;

  int (*qq)[3][4] = new int[2][3][4];
    delete []qq;

4、返回值

//C++ 內(nèi)存申請(qǐng)失敗會(huì)拋出異常
try{
    int *p = new int[10];
}
catch(const std::bad_alloc e) 
{
    return -1;
}
//C++ 內(nèi)存申請(qǐng)失敗不拋出異常版本
int *q = new (std::nothrow)int[10];
if(q == NULL)
    return -1;

5、注意事項(xiàng)

C++中堆空間的分配和釋放注意事項(xiàng)如下:
A、new/delete 是關(guān)鍵字,效率高于 malloc 和 free.
B、配對(duì)使用,避免內(nèi)存泄漏和多重釋放。
C、避免交叉使用。比如 malloc 申請(qǐng)的空間去 delete,new 出的空間被 free;
D、重點(diǎn)用在類(lèi)對(duì)像的申請(qǐng)與釋放。申請(qǐng)的時(shí)候會(huì)調(diào)用構(gòu)造器完成初始化,
釋放的時(shí)候,會(huì)調(diào)用析構(gòu)器完成內(nèi)存的清理。

6、malloc與new區(qū)別

malloc與new的區(qū)別如下:
A、new是C++關(guān)鍵字,malloc是C語(yǔ)言庫(kù)函數(shù)
B、new以具體類(lèi)型為單位進(jìn)行內(nèi)存分配,malloc以字節(jié)位單位分配內(nèi)存
C、new在申請(qǐng)單個(gè)類(lèi)型變量時(shí)可以進(jìn)行初始化,malloc不具備
D、new在所有C++編譯器中都支持,malloc在某些系統(tǒng)開(kāi)發(fā)中不可調(diào)用
E、new能夠觸發(fā)構(gòu)造函數(shù)的調(diào)用,malloc僅分配需要的內(nèi)存空間
F、對(duì)象的創(chuàng)建只能使用new,malloc不適合面向?qū)ο箝_(kāi)發(fā)

7、free與delete的區(qū)別

free與delete的區(qū)別如下:
A、delete是C++關(guān)鍵字,free是庫(kù)函數(shù)
B、delete在所有C++編譯器中都支持,free在某些系統(tǒng)開(kāi)發(fā)中不可調(diào)用
C、delete能夠觸發(fā)析構(gòu)函數(shù)的調(diào)用,free僅歸還分配的內(nèi)存空間
D、對(duì)象的銷(xiāo)毀只能使用delete,free不適合面向?qū)ο箝_(kāi)發(fā)
E、free可以歸還new申請(qǐng)的內(nèi)存空間,但不會(huì)調(diào)用析構(gòu)函數(shù),可能會(huì)造成內(nèi)存泄漏
F、delete可以釋放malloc分配的內(nèi)存空間,但會(huì)調(diào)用析構(gòu)函數(shù),會(huì)造成其他問(wèn)題。

十、內(nèi)聯(lián)函數(shù)

1、內(nèi)聯(lián)函數(shù)簡(jiǎn)介

C語(yǔ)言中有宏函數(shù)的概念。宏函數(shù)的特點(diǎn)是內(nèi)嵌到調(diào)用代碼中去,避免了函數(shù)調(diào)用的開(kāi)銷(xiāo)。但宏函數(shù)的處理發(fā)生在預(yù)處理階段,缺少作用域檢查和類(lèi)型檢查。
C++提供了inline關(guān)鍵字,請(qǐng)求C++編譯器將一個(gè)函數(shù)進(jìn)行內(nèi)聯(lián)編譯(C++編譯器可以拒絕),C++編譯器會(huì)直接將內(nèi)聯(lián)的函數(shù)體代碼插入函數(shù)調(diào)用的地方。
內(nèi)聯(lián)函數(shù)聲明時(shí)inline關(guān)鍵字必須和函數(shù)定義結(jié)合在一起,否則編譯器會(huì)直接忽略?xún)?nèi)聯(lián)請(qǐng)求。

inline int sqr(int x)
{
    return x*x;
}

2、內(nèi)聯(lián)函數(shù)的優(yōu)缺點(diǎn)

內(nèi)聯(lián)函數(shù)的優(yōu)點(diǎn):避免調(diào)用時(shí)的額外開(kāi)銷(xiāo)(入棧與出棧操作)
內(nèi)聯(lián)函數(shù)的缺點(diǎn):內(nèi)聯(lián)函數(shù)的函數(shù)體在代碼段中會(huì)出現(xiàn)多個(gè)“副本”,因此會(huì)增加代碼段的空間。
內(nèi)聯(lián)函數(shù)的本質(zhì):以犧牲代碼段空間為代價(jià),提高程序的運(yùn)行時(shí)間的效率。
內(nèi)聯(lián)函數(shù)的適用場(chǎng)景:函數(shù)體很“小”,且被“頻繁”調(diào)用。

3、內(nèi)聯(lián)函數(shù)示例

Inline關(guān)鍵字是對(duì)編譯器的建議,如果編譯器認(rèn)為inline聲明的函數(shù)可以?xún)?nèi)聯(lián),則編譯器會(huì)將函數(shù)內(nèi)聯(lián),如果編譯器認(rèn)為inline聲明的函數(shù)的函數(shù)體太長(zhǎng),則不會(huì)內(nèi)聯(lián),按普通函數(shù)處理。

using namespace std;

inline int func(int a, int b)
{
    return a*a + b*b;
}

int main(int argc, char *argv[])
{
    int a = 3;
    int b = 4;
    int c = func(a,b);
    return 0;
}

上述代碼在QtCreator+MinGW編譯器下調(diào)試時(shí),查看匯編代碼如下:
C++語(yǔ)言學(xué)習(xí)(二)——C++對(duì)C語(yǔ)言基礎(chǔ)語(yǔ)法的擴(kuò)展
調(diào)用func函數(shù)時(shí),C++編譯器沒(méi)有將func函數(shù)內(nèi)聯(lián),仍然使用函數(shù)調(diào)用。
inline聲明的函數(shù),內(nèi)聯(lián)請(qǐng)求可能被C++編譯器拒絕。
現(xiàn)代C++編譯器能夠進(jìn)行編譯優(yōu)化,一些函數(shù)即使沒(méi)有inline關(guān)鍵字聲明也能夠內(nèi)聯(lián)編譯,同時(shí)現(xiàn)代C++編譯器提供了擴(kuò)展的語(yǔ)法,能夠?qū)瘮?shù)進(jìn)行強(qiáng)制內(nèi)聯(lián)。如現(xiàn)代G++編譯器使用__attribute__((always_inline))聲明強(qiáng)制內(nèi)聯(lián),MSVC編譯器使用__forceinline聲明強(qiáng)制內(nèi)聯(lián),不再使用inline關(guān)鍵字。

#include <iostream>

using namespace std;

__attribute__((always_inline))
int func(int a, int b);

int main(int argc, char *argv[])
{
    int a = 3;
    int b = 4;
    int c = func(a,b);
    return 0;
}

int func(int a, int b)
{
    return a*a + b*b;
}

上述代碼在QtCreator+MinGW編譯器中進(jìn)行調(diào)試時(shí),main函數(shù)中func函數(shù)調(diào)用代碼的匯編代碼如下:
C++語(yǔ)言學(xué)習(xí)(二)——C++對(duì)C語(yǔ)言基礎(chǔ)語(yǔ)法的擴(kuò)展
MinGW編譯器已經(jīng)對(duì)func函數(shù)進(jìn)行了內(nèi)聯(lián)。

4、內(nèi)聯(lián)函數(shù)使用的限制

C++中使用inline關(guān)鍵字內(nèi)聯(lián)編譯函數(shù)的限制:
A、不能存在任何形式的循環(huán)語(yǔ)句
B、不能存在過(guò)多的條件判斷語(yǔ)句
C、函數(shù)體不能過(guò)于龐大
D、不能對(duì)函數(shù)進(jìn)行取地址操作
E、函數(shù)內(nèi)聯(lián)聲明必須在調(diào)用語(yǔ)句前
對(duì)于現(xiàn)代C++編譯器的擴(kuò)展語(yǔ)法提供的強(qiáng)制內(nèi)聯(lián)不受上述條件限制。

十一、類(lèi)型強(qiáng)制轉(zhuǎn)換

1、C++類(lèi)型轉(zhuǎn)換

C語(yǔ)言中的類(lèi)型轉(zhuǎn)換是強(qiáng)制轉(zhuǎn)換,任何類(lèi)型間都可以轉(zhuǎn)換,過(guò)于粗暴。
C++語(yǔ)言引入了static_cast、dynamic_cast、const_cast、reinterpret_cast四個(gè)關(guān)鍵字處理不同類(lèi)型間的轉(zhuǎn)換。

2、靜態(tài)類(lèi)型轉(zhuǎn)換

靜態(tài)類(lèi)型轉(zhuǎn)換是在編譯期內(nèi)即可決定其類(lèi)型的轉(zhuǎn)換。
靜態(tài)類(lèi)型轉(zhuǎn)換的使用場(chǎng)合:
A、用于基本類(lèi)型間的轉(zhuǎn)換
B、不能用于基本類(lèi)型指針間的轉(zhuǎn)換
C、用于有繼承關(guān)系類(lèi)對(duì)象間的轉(zhuǎn)換和類(lèi)指針間的轉(zhuǎn)換(轉(zhuǎn)換一般從子對(duì)象向父對(duì)象轉(zhuǎn)換)
語(yǔ)法格式:

static_cast<目標(biāo)類(lèi)型> (標(biāo)識(shí)符)

應(yīng)用實(shí)例:

#include <stdio.h>

class A
{
private:
    int a;
    int b;
public:
    A()
    {
        a = 0;
        b = 0;
    }
    void print()
    {
        printf("a = %d, b = %d\n", a, b);
    }

};

class B : public  A
{
private:
    int c;
    int d;
public:
    void display()
    {
        printf("c = %d, d = %d\n", c, d);
    }

};

class C
{
public:
    void print()
    {
        printf("hello\n");
    }
};

int main()
{
    float f = static_cast<float>(9)/10;//基本類(lèi)型的轉(zhuǎn)換
    printf("f = %f\n", f);
    A a;
    B b;
    A aa = static_cast<A>(b);//將子類(lèi)對(duì)象轉(zhuǎn)換為父類(lèi)對(duì)象
    aa.print();
    //B bb = static_cast<B>(a);//不能將父對(duì)象轉(zhuǎn)換為子對(duì)象
    A* pa = static_cast<A*>(&a);//在同類(lèi)型對(duì)象指針間轉(zhuǎn)換
    pa->print();
    pa = static_cast<A*>(&b);//將子類(lèi)對(duì)象指針轉(zhuǎn)換為父類(lèi)對(duì)象指針
    pa->print();
    B* pb = static_cast<B*>(&b);
    pb->display();
    pb = static_cast<B*>(&a);
    pb->display();
    //C c = static_cast<C>(a);//沒(méi)有轉(zhuǎn)換構(gòu)函數(shù),不能將A類(lèi)型轉(zhuǎn)換為C類(lèi)型
    //c.print();
    return 0;
}

3、動(dòng)態(tài)類(lèi)型轉(zhuǎn)換

動(dòng)態(tài)類(lèi)型轉(zhuǎn)換的使用場(chǎng)合:
A、用于有繼承關(guān)系的類(lèi)指針間的轉(zhuǎn)換
B、有交叉關(guān)系的類(lèi)指針間的轉(zhuǎn)換
C、具有類(lèi)型檢查
D、必須有虛函數(shù)支持
語(yǔ)法格式:

dynamic_cast<目標(biāo)類(lèi)型> (標(biāo)識(shí)符)

用于有直接或間接繼承關(guān)系的指針(引用)的強(qiáng)制轉(zhuǎn)換
轉(zhuǎn)換指針成功將會(huì)得到目標(biāo)類(lèi)型的指針,轉(zhuǎn)換失敗將得到一個(gè)空指針;
轉(zhuǎn)換引用成功將得到目標(biāo)類(lèi)型的引用,轉(zhuǎn)換失敗將得到一個(gè)異常操作信息。
使用實(shí)例:

#include <iostream>
#include <string>

using namespace std;

class Base
{
public:
    Base()
    {
        cout << "Base::Base()" << endl;
    }
    virtual ~Base()
    {
        cout << "Base::~Base()" << endl;
    }
};

class Derived : public Base
{
};

int main()
{
    Base* p = new Derived;
    Derived* pd = dynamic_cast<Derived*>(p);//將指向子類(lèi)對(duì)象的父類(lèi)指針轉(zhuǎn)換為子類(lèi)指針,轉(zhuǎn)換成功
    if( pd != NULL )
    {
        cout << "pd = " << pd << endl;
    }
    else
    {
        cout << "Cast error!" << endl;
    }
    delete p;
    cout << endl;
    p = new Base;
    pd = dynamic_cast<Derived*>(p);//將指向父類(lèi)對(duì)象的父類(lèi)指針轉(zhuǎn)換為子類(lèi)指針,轉(zhuǎn)換失敗
    if( pd != NULL )
    {
        cout << "pd = " << pd << endl;
    }
    else
    {
        cout << "Cast error!" << endl;
    }
    delete p;
    return 0;
}

4、常量類(lèi)型轉(zhuǎn)換

常量類(lèi)型轉(zhuǎn)換的使用場(chǎng)合:
A、用于去除變量的只讀屬性
B、目標(biāo)類(lèi)類(lèi)型只能是指針或引用
語(yǔ)法格式:

const_cast<目標(biāo)類(lèi)型> (標(biāo)識(shí)符) //目標(biāo)類(lèi)類(lèi)型只能是指針或引用。

const_cast將轉(zhuǎn)換掉表達(dá)式的const屬性
應(yīng)用實(shí)例:

#include <iostream>

using namespace std;

int main()
{
    const int& a = 10;
    int& b = const_cast<int&>(a);//將a的只讀屬性去除,并初始化b
    b = 0;
    cout << "a = " << a << endl;//0
    cout << "b = " << b << endl;//0
    const int c = 100;
    int& d = const_cast<int&>(c);//為c分配一個(gè)只讀空間
    //int x = const_cast<int>(c);//error,目標(biāo)類(lèi)型只能為指針和引用
    d = 1000;
    cout << "c = " << c << endl;//100
    cout << "d = " << d << endl;//1000

    return 0;
}

5、重解釋類(lèi)型轉(zhuǎn)換

重解釋類(lèi)型轉(zhuǎn)換使用場(chǎng)合:
A、用于指針類(lèi)型間的強(qiáng)制轉(zhuǎn)換
B、用于整數(shù)和指針類(lèi)型間的強(qiáng)制轉(zhuǎn)換
語(yǔ)法格式:

reinterpret_cast<目標(biāo)類(lèi)型> (標(biāo)識(shí)符)

為數(shù)據(jù)的二進(jìn)制形式重新解釋?zhuān)遣桓淖兤渲怠?br/>使用實(shí)例:

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    int a = 100;
    char c = 'a';
    int* pa = reinterpret_cast<int*>(&c);
    printf("*pa = %d\n", *pa);//687781729
    printf("*pa = %c\n", *pa);//'a'
    //int x = reinterpret_cast<int>(c);//error
    //int y = reinterpret_cast<int>(1.1);//error

    return 0;
}

十二、命名空間

1、命令空間簡(jiǎn)介

C語(yǔ)言中,只有一個(gè)全局作用域,所有的全局標(biāo)識(shí)符共享一個(gè)作用域,因此標(biāo)識(shí)符之間可能存在沖突。
C++語(yǔ)言中,提出了命名空間的概念。命名空間將全局作用域分為不同的部分,不同命令空間中的標(biāo)識(shí)符可以重名而不會(huì)發(fā)生沖突,命名空間可以嵌套。全局作用域即默認(rèn)命名空間。

2、默認(rèn)命名空間(global &&function)

global scope是一個(gè)程序中最大的scope,是引起命名沖突的根源。C語(yǔ)言沒(méi)有從語(yǔ)言層面提供命名空間機(jī)制來(lái)解決。global scope是無(wú)名的命名空間。

3、命名空間的劃分

NameSpace是對(duì)全局區(qū)域的再次劃分。
命名空間的聲明如下:

namespace NAMESPACE
{
    全局變量 int a;
    數(shù)據(jù)類(lèi)型 struct Stu{};
    函數(shù) void func();
}

4、命名空間的使用方法

直接指定命名空間: NameSpace::a = 5;
使用using+命名空間+空間元素:using NameSpace::a; a = 2000;
使用using +namespace+命名空間;

5、命名空間使用示例

#include <iostream>
using namespace std;
namespace MySpace
{
    int x = 1;
    int y = 2;
}
namespace Other {
    int x = 3;
    int y = 4;
}
int main()
{
    {
        using namespace MySpace;
        cout<<x<<y<<endl;
    }
{
        using namespace Other;
        cout<<x<<y<<endl;
    }
{
        MySpace::x = 100;
        Other::y = 200;
        cout<<MySpace::x<<Other::y<<endl;
    }
    return 0;
}

可以使用塊語(yǔ)句將命名空間限定在塊語(yǔ)句內(nèi)部。

6、命名空間嵌套

namespace MySpace
{
    int x = 1;
    int y = 2;
    namespace Other {
        int m = 3;
        int n = 4;
    }
}

7、使用命名空間進(jìn)行協(xié)作開(kāi)發(fā)

在實(shí)際項(xiàng)目開(kāi)發(fā)中,可以將一個(gè)類(lèi)或者具有相同屬性的多個(gè)類(lèi)聲明在一個(gè)命名空間內(nèi),在使用時(shí)只需要聲明命名空間即可。

#ifndef A_H
#define A_H
namespace XX {
    class A
    {
        public:
            A();
            ~A();
    };
}
#endif // A_H
#include "a.h"
using namespace XXX
{
        A::A()
        {}
        A::~A()
        {}
}

十三、系統(tǒng)string類(lèi)

除了使用字符數(shù)組來(lái)處理字符串以外,C++引入了字符串類(lèi)型??梢远x字符串變量。

1、定義和初始化

  string str;
  str = "china";
    string str2 = " is great ";
    string str3 = str2;

2、類(lèi)型大小

string str = "china";
cout << sizeof(str) << " " << str.max_size() << " " << str.size()<<endl;

4 1073741820 5

3、運(yùn)算

A、賦值
string str3 = str2;
B、加法
string combine = str + str2;
C、關(guān)系

string s1 = "abcdeg";
string s2 = "12345";
if(s1>s2)
cout<<"s1>s2"<<endl;
else
cout<<"s1<s2"<<endl;

4、string類(lèi)型數(shù)組

string數(shù)組是高效的,如果用二維數(shù)組來(lái)存入字符串?dāng)?shù)組的話,則容易浪費(fèi)空間,此時(shí)列數(shù)是由最長(zhǎng)的字符串決定。如果用二級(jí)指針申請(qǐng)堆空間,依據(jù)大小申請(qǐng)相應(yīng)的空間,雖然解決了內(nèi)存浪費(fèi)的問(wèn)題,但是操作麻煩。用 string 數(shù)組存儲(chǔ),字符串?dāng)?shù)組的話,效率即高又靈活。

string sArray[10] = {
    "0",
    "1",
    "22",
    "333",
    "4444",
    "55555",
    "666666",
    "7777777",
    "88888888",
    "999999999",
};
for(int i=0; i<10; i++)
{
    cout<<sArray[i]<<endl;
}

5、string類(lèi)的成員函數(shù)

int capacity()const;??//返回當(dāng)前容量(即string中不必增加內(nèi)存即可存放的元素個(gè)數(shù))
int max_size()const;??? //返回string對(duì)象中可存放的最大字符串的長(zhǎng)度
int size()const;??????? //返回當(dāng)前字符串的大小
int length()const;?????? //返回當(dāng)前字符串的長(zhǎng)度
bool empty()const;??????? //當(dāng)前字符串是否為空
void resize(int len,char c);//把字符串當(dāng)前大小置為len,并用字符c填充不足的部分
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI