C++概述
C++誕生
1972年前后,計算機先驅丹尼斯·里奇開始設計C語言并用它來重寫Unix系統,里奇的這個決定催生了計算機領域最石破天驚的兩門重炮:Unix和C,這兩者都是IT產業中鼻祖級的存在,Unix是現代蘋果系統和Linux系統的最初來源,而C則是現代眾多編程語言的思想源泉。后來隨著IT產業的發展,C語言加入了諸如面向對象、泛型編程等新特性,在1983年前后,貝爾實驗室的Biarne Strau-strup(本賈尼·斯特勞斯特盧普)推出了現代編程界中威力最猛的一門重炮:C++。
c++之父「Bjarne Strou-strup」
C++進一步擴充和完善C語言,成為一種多種編程范式的程序設計語言。從其名稱可以推斷,這種編程語言與C語言有密切的聯系,實際上它們通常被合稱為C/C++,它們的關系主要體現在以下兩點:
- C++是C語言的超集, C語言是C++語言聯邦的一部分。
- C++完全兼容C語言,并提供眾多火力強大的現代編程范式。
C與C++
據統計,當今世界上不同的編程語言有幾百種之多, C++是使用最廣泛的編程語言之一,是名副其實的頂流。 C++強大的同時,也是一門比較復雜的語言,它還包括函數式編程、泛型編程等不同的編程范式,有人說C++不是一門編程語言,而是眾多編程語言的合集。
C++能干什么
C++主要用在開發系統、算法核心、游戲引擎等對性能高度敏感的領域,除了性能出眾, C++的高安全性也是首屈一指的。下面簡單羅列C++在IT各開發領域所展露的強大生
命力。
游戲 C++非常適合開發游戲,它的超前設計在應對3D游戲的復雜性時游刃有余, C++對網絡的良好支持使得開發大型多人同時在線游戲成為可能,更進一步,由于C++允許直接控制硬件,因此能極大釋放CPU的潛能,這種高性能使得C++被廣泛應用于不同的游戲和游戲引擎。
動畫 許多動畫軟件都是用C++開發的, C++非常適合用于圖像處理、視覺效果呈現等典型的資源消耗型軟件,比如:三維動畫、建模、仿真、渲染,尤其是虛擬現實VR的場景和角色創建。
瀏覽器 C++也適合于用來開發瀏覽器,比如微軟著名瀏覽器IE,谷歌的 Chrome
和 Fire Fox
等,都是C++編寫的, C++還是谷歌和Mozilla開源項目的核心呈現引擎的編程語
言。
數據庫 C++在數據庫軟件開發中也占據非常重要的地位,最流行的數據庫管理軟件 MySQ L
就是其中一例, C++有助于節省時間、成本,提高業務系統的開發效率,還有大量基于
數據庫軟件訪問的應用程序,主要都使用C++開發,這使得數據庫訪問快速、準確。
多媒體 C++當然可以用于創建媒體播放器,管理音視頻文件等,它使得我們享受音樂,訪
問和分享視頻和音樂文件。相關的C++類庫還具有藝術支持、音頻和視頻流媒體等功能。
甚至提供互聯網無線電臺的接入。
編譯系統 大多數的編譯器都使用C++開發,編譯器是一種將計算機語言翻譯成機器指令的特殊軟件,比如C#、 Java等語言的編譯器都是由C++進行翻譯,然后才能交給CPU去運行。 C++在底層層面為各種各樣軟件的移植性提供支持。
? 從這方面理解, C和C++是編寫其他語言的語言,是許多編程語言的母語言。
操作系統 開發編譯系統和操作系統,從某種程度上講是C/C++當初被設計出來的初衷,如今世界上通行的底層操作系統幾乎全部都是C/C++開發的,比如微軟的 Windows2000
和XP
, Unix/Linux
系統,安卓系統和蘋果公司的部分操作系統。
應用開發 圖形應用軟件領域也大量廣泛使用C++開發,比如被著名的圖形設計軟件 Phot oShop
、 Adobe
系列軟件,微軟的 Office
辦公套件和Visual Studio
,還有大量應
用于人工智能領域的算法引擎。
小結
? 由于出生年代較早, C/C++并不是最易用、語法結構最淺顯的語言,這主要是因為早期的計算機資源有限,計算機科學家在開發C/C++的時候,最在意的是最終代碼運行的效率,而遠非代碼編寫的難易度,這導致C/C++可以支持非常貼近底層硬件細節的語法,抓地力非常強,因而學習曲線要比一般的編程語言陡峭,也就是對學習者的要求更高。
? 但也正是因為以上原因, C/C++天生具有高性能的血統,在目前的IT產業中,凡是涉及底層系統、算法核心、游戲引擎等對性能敏感的領域, C/C++都扮演者著不可或缺的角色,因為這些部件哪怕1%的性能波動,都會對整個軟件的體驗帶來本質的改變。 總體來講, C/C++是一門難學易用的編程語言,是計算機編程領域的重裝武器,一旦掌握,威力無比。
C++輸入輸出
概述
在C++ 中輸入和輸出操作可以通過標準庫中的iostream
頭文件來實現。這個頭文件提供了類和對象,用于處理輸入流(istream)和輸出流(ostream)。最常見的來個對象是cin
(控制臺輸入)和cout
(控制臺輸出)。
包含頭文件
為了使用輸入輸出功能必須包含以下頭文件#include <iostream>
輸出到控制臺
使用cout
對象可以將數據輸出到控制臺。<<
運輸符 (用于將數據插入到輸出流中)。
(cout
相當于一個面向對象的結構體)
typedef struct
{int id;char *name;
}Student;
Student stu;// stu是學生對象
//stu.id 和 stu.name 是對象的成員
基本用法
// 如果不想寫std :: 可以在文件頂部添加聲明,using namespace std;
std ::cout << "hello World";// 開口方向是數據流方向
// 類似于C語言中的 printf("hello world \n");
輸出多個值
int number = 10;
std:: count << "number" <<"number"; // 輸出:number :10
從控制臺輸入
使用cin
對象可以從控制臺讀取用戶輸入。>>
運輸符(用于從輸入流中讀取數據)
基本用法
int age;
std::cout << "請輸入您的年齡";
std::cin >> "age";
std::cout << "您今年" << "age" << " 歲 " << " \n ";
處理字符串輸入
對于字符串類型,建議使用getline
函數,因為他可以讀取包含空格的整行文本。
#include <string>std::string name ;// 字符串類型的變量
std::cout << "請輸入您的名字";
std::getline(std::cin,name); // 相當于C語言中的scanf("%s",&name)
std::cout << "你好", << "name" << "!\n";
格式化輸出
可以使用操縱器來格式化輸出,例如設置數字的顯示方式、填充字符等。
設置精度
double pi = 3.1415926;
std:: cout.self(std:: ios::fixed);// 固定小數點表示法
std:: cout.precision(2); // 和上面代碼配套使用,設置小數保留為2
std:: cout<< "PI 的近似值:" << pi << "\n" ;// 輸出結果,PI 的近似值:3.14
對齊方式
//c++ 標準庫中的一個頭文件, 提供了多種用于控制輸入輸出格式的操縱器( manipulators) , 通過使用`<iomanip>`, 可以方便的格式化輸入輸出數據, 例如試著小數位數、 對齊方式、 填充字符等。
#include <iomanip>int num = 42;
std::cout.width(10); // 設置字段寬度為10, 也就是c語言的%m
std::cout.fill("*"); // 填充字符為*
std::cout << std:: left << num << "\n"; // 左對齊輸出, 輸出結果:
std::cout << std:: right << num << "\n"; // 右對齊輸出, 輸出結果:
完整的代碼
/*************************************************************************> File Name: demo01.cpp> Author: 小劉> Description: 控制臺的輸入輸出> Created Time: 2025-08-18 10:46:58************************************************************************/
#include <iostream>
#include <iomanip>
#include <string>// 聲明使用命名空間
using namespace std;int main()
{// 聲明一個字符串的變量string name;int age;cout << "請輸入您的名字:";getline(cin,name);cout << "請輸入您的年齡:";cin >> age ;double height ;cout << "請輸入您的身高(米)";cin >> height;cout << " 個人信息 :" << endl; // cout << " 姓名 : " << name << " \n";cout << " 年齡 : " << age << endl;cout.setf(ios :: fixed);cout.precision(2);cout << " 身高: " << height << endl;return 0;
}
內存分區模型
C++ 程序執行時,將內存大方向劃分為4個區域
-
代碼區:存放函數體的二進制代碼,由操作系統進行管理
-
全局區:存放全局變量和靜態變量以及常量
-
堆區:由編譯器自動分配釋放,存放函數的形參值,局部變量等。
-
棧區:由程序員分配和釋放,若程序員不釋放,程序結束時由操作系統回收。
內存四區意義:
不同區域存放的數據,賦予不同的生命周期給我們大量的靈活編程。
程序運行前
在程序編譯后,生成了exe可執行程序,未執行該程序前分為兩個區域
代碼區:
? 存放CPU執行的機器指令
? 代碼區是共享的,共享的目的是對于頻繁被執行的程序,只需要在內存中有一份代碼即可
? 代碼區是只讀的,使其只讀的原因是防止程序意外地修改了它的指令
全局區:
? 全局變量和靜態變量存放在此
? 全局區還包含了常量區,字符串常量和其他常量也存放在此
? 該區域的數據在程序結束后由操作系統釋放
案例:
/*************************************************************************> File Name: demo03.cpp> Author: 小劉> Description: 內存分區模型> Created Time: 2025-08-18 14:39:47************************************************************************/
#include <iostream>
#include <iomanip>// 使用std命名空間
using namespace std;// 全局變量:定義在函數外部,默認有初始值是0 \0 NULL
int g_a = 10;
int g_b = 10;// 全局常量:只能賦值一次,一般通過初始值賦值
const int c_g_a = 10;
const int c_g_b = 10;int main()
{// 局部常量:寫在函數或者語句塊的常量int a = 10;int b = 10;// 打印局部變量地址cout << "局部變量a 的地址:" << &a << endl;cout << "局部變量b 的地址:" << &b << endl;// 打印全局變量地址cout << "全局變量g_a 的地址:" << &g_a << endl;cout << "全局變量g_b 的地址:" << &g_b << endl;// 靜態變量 存儲在數據區static int s_a = 10;static int s_b = 10;// 打印靜態變量地址cout << "靜態變量s_a 的地址:" << &s_a << endl;cout << "靜態變量s_b 的地址:" << &s_b << endl;cout << "全局常量c_g_a 的地址:" << &c_g_a << endl;cout << "全局常量c_g_b 的地址:" << &c_g_b << endl;cout << "字符串常量的地址:" << &"hello world" << endl;cout << "字符串常量的地址:" << &"hello world1" << endl;// 只讀常量 | 局部常量const int c_l_a = 10;const int c_l_b = 10;cout << "局部常量c_l_a 的地址" << &c_l_a <<endl;cout << "局部常量c_l_b 的地址" << &c_l_b <<endl;return 0;
}
總結
- C ++中在程序運行前分為全局區和代碼區
- 代碼區特點是共享和只讀
- 全局區中存放全局變量、靜態變量、常量
- 常量區中存放const修飾的全局常量和字符串常量
程序執行后
棧區:
? 由編譯器自動分配釋放,存放函數的參數值,局部變量等
? 注意事項:不要返回局部變量的地址,棧區開辟的空間由編譯器釋放
示例:
int* func()
{int a = 10;return &a; // 返回a 的地址
}int main()
{int *p = func();cout << *p << endl; // 此時p是有值的,存放的就是func中a的地址,但是由于func整體的內存回收所以導致p地址對應的空間不存在,此時這種現象就屬于懸掛指針(空懸指針),它是野指針的一種體現。//ststem("pause");return 0;
}
堆區:
? 由程序員分配釋放,若程序員不釋放,程序結束后由操作系統回收。
? 在C++主要利用new在堆區開辟內存。
int func()
{int *a = new int(10); // 等價于 int* a = malloc(sizeof(int));return 0;
}int main()
{int *p = func();cout << *p << endl;return 0;
}
總結:
堆區數據由程序員管理開辟和釋放
堆區數據利用new關鍵字進行開辟內存,利用delete關鍵字釋放內存
new操作符
C++中利用new 操作符在堆區開辟內存。
堆區開辟的內存,由程序員手動開辟,手動釋放,釋放利用操作符delete
語法:
new 數據類型;
delete 變量;
利用new創建的內存,會返回內存空間的指針。
示例1基本語法
/*************************************************************************> File Name: demo03.cpp> Author: 小劉> Description: new 操作符> Created Time: 2025-08-18 15:39:41************************************************************************/
#include <iostream>
#include <iomanip>using namespace std;int* func()
{int *a = new int(10); // 在堆區內存申請4字節的空間,存放一個初始數據10return a;
}
int main()
{int *p = func();cout << *p << endl; //10// 利用delete釋放堆區數據delete p ;cout << *p << endl;// 報錯,釋放的空間不可訪問return 0;
}
示例2:開辟數據組
/*************************************************************************> File Name: demo04.cpp> Author: 小劉> Description: new操作符,開辟數組> Created Time: 2025-08-18 15:45:51************************************************************************/
#include <iostream>
#include <iomanip>using namespace std;int main()
{int * arr = new int [10];// int(10) 初始化數據位10 ,int[10] 指定數組大小for(int i=0;i<10;i++){arr[i] = i + 100;}for(int i=0;i<10;i++){cout << arr[i] << endl;}delete[] arr;return 0;
}
面試題:new與 malloc的區別?
-
聯系:
1.1 new和malloc都可以用來申請堆內存,new運算符內部實現仍然調用了malloc,
1.2 new和malloc作用于基礎數據類型,兩者沒有區別;
-
區別:
2.1 性質上:new是運算符,malloc是函數
2.2內存申請上,malloc是要指明申請的內存大小,new會根據目標類型申請內存;
2.3返回數據類型,malloc只返回void*,new會返回目標類型的指針;
2.4從底層實現原理上,malloc只負責空間申請,new不僅要空間申請,還要負責對象構造。
涉及術語:自由存儲區自由存儲區:用new運算符申請的內存成為自由存儲區C++標準庫提供的new運算符內部調用了malloc所以此時的自由存儲區就是堆區,但C++支持運算符重載,如果我們對new運算符進行了重載,可能在內存申請上就可以從堆區外的其他區域申請,此時的自由存儲區就不是堆區了。
引用
引用的基本使用
**作用:**給變量起別名
語法:
數據類型 &別名 = 原名
示例:
/*************************************************************************> File Name: demo05.cpp> Author: 小劉> Description: 引用> Created Time: 2025-08-18 15:36:43************************************************************************/
#include <iostream>
#include <iomanip>using namespace std;int main()
{// 定義一個變量int a = 10;// 定義引用int &b = a; // 此時a和b的空間是共享的,也就是b的空間是它的引用的對象a的空間 真正的引用是b & 是一個操作符cout << "a = " << a << endl; // a = 10cout << "b = " << b << endl; // b = 10cout << "a 的地址 " << &a << endl; //a 的地址 0x7f5bdffba4cout << "b 的地址 " << &b << endl; //b 的地址 0x7f5bdffba4b = 100;cout << "a = " << a << endl; // a = 100cout << "b = " << b << endl; // b = 100int aa = 10;int *p = &aa;cout << "aa 的地址 " << &aa << endl; //aa 的地址 0x5c725ff750cout << "p 的地址 " << &p << endl; //p 的地址 0x5c725ff748return 0;
}
引用注意事項
- 引用必須初始化,否則沒有意義
- 引用在初始化后,不可以改變
引用特點:
①引用不可以改變
②引用對象的值可以改變
示例:
/*************************************************************************> File Name: demo06.cpp> Author: 小劉> Description: 引用相關案例> Created Time: 2025-08-18 15:51:25************************************************************************/
#include <iostream>
#include <iomanip>using namespace std;int main()
{int a = 10;int b = 20;// int &c; 錯誤,引用必須初始化int &c = a;// 一旦初始化后,就不可以改變c = b; // 這是賦值操作,不是改變引用cout << "a = " << a << endl; // a = 20cout << "b = " << b << endl; // b = 20cout << "c = " << c << endl; // c = 20return 0;
}
引用做函數參數
**作用:**函數傳參時,可以引用的技術讓形參修飾實參
**優點:**可以簡化指針修改實參
示例
/*************************************************************************> File Name: demo07.cpp> Author: 小劉> Description: 值傳遞、地址傳遞、引用傳遞> Created Time: 2025-08-18 15:57:19************************************************************************/
#include <iostream>
#include <iomanip>using namespace std;/*
* 1.值傳遞
*/
void mySwap01(int a, int b)
{int temp = a ;a = b;b = temp;
}/*
* 2.地址傳遞
*/
void mySwap02(int* a, int* b)
{int temp = *a ;*a = *b;*b = temp;
}/*
* 3.引用傳遞(C語言不支持)
*/
void mySwap03(int& a, int& b)
{int temp = a ;a = b;b = temp;
}int main()
{int a = 10 ,b = 20; mySwap01(a,b); // 普通的值傳遞,形參和實參空間是獨立的cout << "a = " << a << ", b = " << b << endl;mySwap02(&a,&b); // 地址傳遞,形參和實參空間是共享的cout << "a = " << a << ", b = " << b << endl;mySwap02(&a,&b); // 引用傳遞,形參就是使用實參的空間cout << "a = " << a << ", b = " << b << endl;return 0;
}
總結:通過引用參數的效果同按地址傳遞一樣的。引用的語法更清楚簡單
引用做函數返回值
**作用:**引用是可以作為函數的返回值存在的。
**注意:**不要返回局部變量的引用。因為會產生野指針。
示例
/*************************************************************************> File Name: demo08.cpp> Author: 小劉> Description: > Created Time: 2025-08-18 16:12:13************************************************************************/
#include <iostream>
#include <iomanip>using namespace std;/*
* 返回局部變量引用
*/int& text01()
{
int a = 10;
return a;
}/*
* 返回局部變量引用
*/
int& text02()
{static int a = 20; // 局部變量cout << "a = " << a << endl; return a;
}int main()
{// 不能返回局部變量的引用//int& ref = text01();// cout << "ref = " << ref << endl; // 這種寫法有問題,因為引用的空間已經提前釋放了int& ref2 = text02();cout << "ref2= " << ref2 << endl;text02() = 1000;cout << "ref2= " << ref2 << endl;text02();return 0;
}
引用本質
本質:引用的本質在C++內部實現是一個指針常量
示例:
// 發現是引用, 轉換為 int* const ref = &a;
void func(int& ref){
ref = 100; // ref是引用, 轉換為*ref = 100
}
int main(){int a = 10;//自動轉換為 int* const ref = &a; 指針常量是指針指向不可改, 也說明為什么引用不可更改int& ref = a;ref = 20; //內部發現ref是引用, 自動幫我們轉換為: *ref = 20;cout << "a:" << a << endl;cout << "ref:" << ref << endl;func(a);return 0;
}
結論:C++推薦用應用技術,因為方便,引用本質是指針常量,但是所有的指針操作編譯器都幫我們做了
常量引用
**作用:**常量引用主要用來修飾形參,放置誤操作
在函數新參列表中可以加const 修飾形參
,防止形參改變實參
/*************************************************************************> File Name: demo09.cpp> Author: 小劉> Description: 常量引用> Created Time: 2025-08-18 16:55:03************************************************************************/
#include <iostream>
#include <iomanip>using namespace std;// 引用使用場景,通常來修飾形參
void showValue(const int& v)
{//v+= 10 ;等價于 v = v + 10;cout << v << endl;
}int main()
{// int& ref = 10; 引用本身需要一個合法的內存空間// 加入const就可以了, 編譯器優化代碼: int temp = 10; const int& ref = temp;const int& ref = 10;// ref = 100; // 加入coust 后不可以修改變量cout << ref <<endl; // 10// 函數中利用常量引用防止誤操作修改實參int a =20;showValue(a);return 0;
}
思考題:
? 什么是零拷貝?
函數擴展
函數默認參數
在C++中,函數的形參列表中的形參可以有默認值。
語法:
返回值類型 函數名( 參數 = 默認值) {}
示例:
/*************************************************************************> File Name: demo10.cpp> Author: 小劉> Description: > Created Time: 2025-08-18 17:24:22************************************************************************/
#include <iostream>
#include <iomanip>using namespace std;int func(int a, int b = 10,int c = 10)// 如果有對應的實參賦值操作, 形參默認值失效
{return a + b + c;
}int main()
{cout << "rst = " << func(20,20) << endl;// ret = 50 如果有實參, 使用實參數據, 如果無實參, 使用形參默認數據cout << "rst = " << func(100) << endl;// ret = 120return 0;
}
函數占位參數
C++ 中函數的形參列表里有占位參數,用來做占位,調用函數時必須填補該位置
語法: 返回值類型 函數名 (數據類型){}
在現階段函數的占位參數存在意義不大,但是后面的課程中會用到該技術
示例:
//函數占位參數 , 占位參數也可以有默認參數
void func(int a, int) {cout << "this is func" << endl;
}int main() {func(10,10); //占位參數必須填補system("pause");return 0;
}
函數重載
函數重載概述
**作用:**函數名可以相同,提高復用性
函數重載滿足的條件
- 同一個作用域下(比如同一個文件中)
- 函數名稱相同
- 函數參數類型不同或者參數個數不同或者順序不同
**注意:**函數的返回值不可以作為函數重載的條件,也就是說函數重載跟返回值無關。
示例:
// 函數重載需要函數都在同一個作用域下, 比如在同一個文件中
void func()
{cout << "func 的調用! " << endl;
}
void func(int a)
{cout << "func (int a) 的調用! " << endl;
}
void func(double a)
{cout << "func (double a)的調用! " << endl;
}
void func(int a ,double b)
{cout << "func (int a ,double b) 的調用! " << endl;
}
void func(double a ,int b)
{cout << "func (double a ,int b)的調用! " << endl;
} //函數返回值不可以作為函數重載條件
//int func(double c, int d)
//{
// cout << "func (double c ,int d)的調用! " << endl;
//}int main() {func();func(10);func(3.14);func(10,3.14);func(3.14 , 10);system("pause");return 0;
}
函數重載注意事項
- 引用作為重載條件
- 函數重載碰到函數默認參數
示例:
/*************************************************************************> File Name: demo11.cpp> Author: 小劉> Description: 函數重載(函數重載注意事項)> Created Time: 2025-08-18 17:37:33************************************************************************/
#include <iostream>
#include <iomanip>using namespace std;/*
* 1.引用作為重載條件
*/
void func(int &a) // 引用不占用任何內存空間,引用的值可變
{cout << "func(int &a) 調用" << endl;
}void func(const int &a) //常量引用,引用的值不可變,一般只讀操作
{cout << "func(const int &a) 調用" << endl;
}/*
* 2.函數重載碰到函數默認參數
*/
void func2(int a ,int b = 10)
{cout << "func(int a,int b = 10) 調用" << endl;
}void func2(int a)
{cout << "func(int a) 調用" << endl;
}int main()
{int a = 10;func(a); // 調用無constfunc(10); // 調用有constfunc2(10,20); // func2(10); // 碰到默認參數產生歧義,需要避免return 0;
}