【C++】初識C++之C語言加入光榮的進化(上)

寫在前面

本篇筆記作為C++的開篇筆記,主要是講解C++關鍵字(C++98)連帶一點點(C++11)的知識。掌握的C++新語法新特性,當然C++是兼容C的,我們學習C的那套在C++中也是受用。

ps:點我跳轉下集


文章目錄

  • 寫在前面
  • 一、命名空間域
    • 1.1、命名空間域的定義與使用
    • 1.2、命名空間域的細節
  • 二、 C++的輸入/輸出
    • 2.2、關于std命名空間的使用慣例
  • 三、缺省參數
  • 四、函數重載
    • 4.1、深入了解C++的重載機制
  • 五、C++98關鍵字


一、命名空間域

在C/C++中,變量、函數和后面要學到的類都是大量存在的,這些變量、函數和類的名稱將都存在于全局作用域中,可能會導致很多沖突。使用命名空間的目的是對標識符的名稱進行本地化,以避免命名沖突或名字污染namespace關鍵字的出現就是針對這種問題的。

在這里插入圖片描述
我們在全局中定義一個變量rand,但是rand函數在stdllib.h庫中已經定義,根據我們學習過的程序的程序編譯與鏈接筆記提到過,在連接中出現相同的變量符號表合并時會報錯。
在這里插入圖片描述
為了避免這種情況C++推出了新的關鍵字namespace,命名空間域。這樣在全局中,我們就保護了我們自己定義的rand變量。在這里插入圖片描述

1.1、命名空間域的定義與使用

定義命名空間,需要使用到 namespace關鍵字,后面跟命名空間的名字,然后接一對{} 即可,{}中即為命名空間的成員。
在這里插入圖片描述

這時候我們運行程序,發現打印結果并不是我們自己創建的全局變量rand,如下圖
在這里插入圖片描述
這是因為被命名空間域保護起來的變量外界不能直接訪問

命名空間的使用有三種方式:

  • 加命名空間名稱及作用域限定符( :: )
namespace Bucai {int rand = 10;int k = 20;
}
int main()
{printf("%d\n", Bucai::k);return 0;
}
  • 使用using將命名空間中某個成員引入
namespace Bucai {int rand = 10;int k = 20;
}
using Bucai::k;
int main()
{printf("%d\n", k);return 0;
}
  • 使用using namespace 命名空間名稱 引入
    這個效果是暴露命名空間域的內容,讓外部可以直接訪問。但是這和直接全局中定義變量的效果是不一樣的,因為在命名空間域中有標識,在編譯連接中形成的符號表不會與在全局變量中定義的吻合
#include <stdio.h>
#include <stdlib.h>namespace Bucai {int rand = 10;int k = 20;
}using namespace Bucai;int main()
{printf("%d\n", k);return 0;
}

但是需要注意的是,如果在上面代碼中,我們直接使用rand會,程序會報錯,如下圖在這里插入圖片描述
報出錯誤是rand不明確符號,不再是之前的重定義,所以我們使用using namespace命名空間名稱引入,需要留意直接引入后的結果。


1.2、命名空間域的細節

命名空間域也是域,它與作用域的細節是相似的,代碼塊就是作用域的一種表現形式,我們使用代碼塊理解命名空間域會更好,在代碼塊中,我們定義的變量等與外界是互不干涉的,而且在代碼塊中我們使用對應的變量采用的是就近原則,而且在代碼塊中可以嵌套代碼塊,在代碼塊外面訪問不了代碼塊的內容,因為在代碼塊中的內容出了代碼塊作用域就結束。

命名空間域我們可以理解為一個有名稱的代碼塊。必須定義在全局中的"代碼塊",在域中可以隨意的定義變量,這樣外界不會與域中變量命有沖突,當我們想要使用域中變量時,可以通過域名+作用域限定符來完成引用

命名空間域細節:

  1. 命名空間中可以定義變量/函數/自定義類型/類
namespace Bucai {int rand = 10;int k = 20;int Add(int left, int right){return left + right;}class MyName {public:int age = 18;};
}
  1. 命名空間可以嵌套
namespace Bucai {int k = 0;namespace bbbb {int age = 18;}
}
  1. 同一個工程中允許存在多個相同名稱的命名空間,編譯器最后會合成同一個命名空間中。

二、 C++的輸入/輸出

C++兼容C,自然是支持C的標準輸入輸出的,但是C的標準輸入輸出有點麻煩,每次都需要程序猿手動標識這個變量是上面類型,需要使用%什么來進行輸出,很麻煩,所以C++推出了一個全新玩法。

#include<iostream>
// std是C++標準庫的命名空間名,C++將標準庫的定義實現都放到這個命名空間中
using namespace std;//在平時練習中我們可以直接展開std命名空間域
int main()
{cout << "Hello world" << endl;return 0;
}

說明:

  1. 使用cout標準輸出對象(控制臺)和cin標準輸入對象(鍵盤)時,必須包含<iostream>頭文件以及按命名空間使用方法使用 std
  2. coutcin是全局的流對象endl是特殊的C++符號,表示換行輸出(即C中的\n),他們都包含在包含<iostream>頭文件中。
  3. <<是流插入運算符,>>是流提取運算符
  4. 使用C++輸入輸出更方便不需要printf/scanf輸入輸出時那樣,需要手動控制格式C++輸入輸出可以自動識別變量類型
  5. 實際上coutcin分別是ostreamistream類型的對象,>><<也涉及運算符重載等知識。后面不才專門寫一篇筆記來講解IO流用法及原理。
  6. C++中為了兼容C語言,在C++ 使用流輸入輸出時需要檢查C語言的輸入輸出,從原理的角度說,C++ 的輸入輸出效率是比C語言的輸入輸出要低的

注意: 早期標準庫將所有功能在全局域中實現,聲明在.h后綴的頭文件中,使用時只需包含對應頭文件即可,后來將其實現在std命名空間下,為了和C頭文件區分,也為了正確使用命名空間,規定C++頭文件不帶.h;舊編譯器(vc 6.0)中還支持<iostream.h>格式,后續編譯器已不支持,因此推薦使用<iostream>+std的方式來使用。
在這里插入圖片描述

#include <iostream>
using namespace std;
int main()
{int a;double b;char c;// 可以自動識別變量的類型cin >> a;cin >> b >> c;cout << endl << a << endl;cout << b << "  " << c<< "  " << 12.888 << endl;return 0;
}

測試運行結果:
在這里插入圖片描述


2.2、關于std命名空間的使用慣例

std是C++標準庫的命名空間

  1. 日常練習中,建議直接using namespace std即可,這樣就很方便。
  2. 項目開發中,using namespace std展開,標準庫就全部暴露出來了,但是項目開發中代碼較多、規模大,就很容易出現沖突問題。所以建議在項目開發中使用,像std::cout這樣使用是 指定命名空間 + using std::cout展開常用的庫對象/類型等方式

三、缺省參數

缺省參數是聲明或定義函數時為函數的參數指定一個缺省值。在調用該函數時,如果沒有指定實參則采用該形參的缺省值,否則使用指定的實參。

在這里插入圖片描述

void Func(int a = 20)
{cout << a << endl;
}
int main()
{Func();		// 沒有傳參時,使用參數的默認值Func(10);	// 傳參時,使用指定的實參return 0;
}

測試運行結果:
在這里插入圖片描述
在上結果圖中,我們也可以看出在函數定義中,我們設計了一個形參,但是形參給了一個缺省值20,在我們調用函數時,我們沒有給形參a傳遞實參時,a就使用缺省值,所以打印20,在我們有傳遞實參時,形參就接收實參參數,缺省值就失效了,所以打印10

缺省參數類型:

  • 全缺省參數
void Func(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}
  • 半缺省參數
    • 半缺省參數必須從右往左依次來給出,不能間隔著給
    • 缺省參數不能函數聲明和定義同時出現,如果函數聲明和定義分開,缺省參數需要在聲明中指定
    • 缺省值必須是常量或者全局變量
    • C語言不支持(編譯器不支持)
void Func(int a, int b = 10, int c = 20)//從右往左依次指定缺省值
{cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;
}

傳參時編譯器讀取實參是從左往右讀取的,如果不是右往左指定缺省值,那么在實參傳遞時,會出現程序猿意想之外的錯誤,所以編譯器會檢查缺省值的給定,若出現缺省值的指定不是從右往左,則報錯,如下圖。
在這里插入圖片描述
函數聲明與定義分開的工程中,如果我們把缺省值放在定義中會出現報錯:如下程序

//test.h
void Func(int a, int b, int c);//tect.c
#include "test.h"
void Func(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}//main.c
#include "test.h"
int main() {Func();return 0;
}

測試結果:在這里插入圖片描述
程序編譯與鏈接筆記中,我們已經知道#include引用的頭文件,最后都是拷貝頭文件內容到當前文件下的。
test.h頭文件中,我們只聲明了沒有缺省值的Func函數,在編譯階段拷貝到工程中,就不是有缺省值的函數,所以報錯。


四、函數重載

自然語言中,一個詞可以有多重含義,人們可以通過上下文來判斷該詞真實的含義,即該詞被重載了。
比如:以前有一個笑話,國有兩個體育項目大家根本不用看,也不用擔心。一個是乒乓球,一個是男足。前者是“誰也贏不了!”,后者是“誰也贏不了!”。

誰也贏不了雖然是一樣的字,但是意思完全不一樣,這就形成了重載,同理,C++中也做出了相似的函數重載。

函數重載: 是函數的一種特殊情況,C++允許在同一作用域中聲明幾個功能類似的同名函數要求這些同名函數形參列表 (參數個數類型類型順序) 不同,常用來處理實現功能類似數據類型不同的問題。

在這里插入圖片描述
我們設計一個交換函數,用來交換變量值:

void Swap(int* a, int* b) {  int num = *a;*a = *b;*b = num;
}
void Swap(double *a, double *b) {double num = *a;*a = *b;*b = num;
}int main() {int a = 10, b = 20;Swap(&a, &b);cout << "a = " << a << " b = " << b << endl;double c = 10.12, d = 20.12;Swap(&c, &d);cout << "c = " << c << " d = " << d << endl;return 0;
}

運行結果:
在這里插入圖片描述
這樣我們就完成了不同類型的變量交換,Swap函數形成了重載,這時C++編譯器特有的屬性

構成重載的三大要素:

  1. 形參個數不同
  2. 形參類型順序不同
  3. 形參類型不同

注意:函數的返回值不同是不構成函數重載的!!


4.1、深入了解C++的重載機制

在深入了解之前,我們先認識一下C語言為什么不支持重載,但在此之前我們需要清楚C/C++的程序編譯與鏈接,因為重載機制核心是發生在編譯階段完成的。

在C語言中,我們根據不才寫的程序編譯與鏈接筆記可以知道,在程序在經過編譯后我們的函數符號名是不會有改變的。我們以下程序為例:

#include <stdio.h>void Swap(int* a, int* b) {  int num = *a;*a = *b;*b = num;
}int main(){int a = 10;int b = 20;Swap( &a,&b);printf("%d \n",a);return 0;
}

我們在Linux環境下查看上面C語言生成的符號表(如下圖)
在這里插入圖片描述
在上圖中,可以清晰看出在C語言中函數符號名有且只有一個,這樣就導致了C語言的編譯器不支持重載,而C++推出了全新玩法把編譯后的函數符號名更改為另一種形式函數符號名,讓其實現函數的重載

在Windows環境下,函數命名太過復雜,不才這里使用 g++編譯器

我們以上面代碼為例:

#include <stdio.h>void Swap(int* a, int* b) {  int num = *a;*a = *b;*b = num;
}int main(){int a = 10;int b = 20;Swap( &a,&b);printf("%d \n",a);return 0;
}

我們在Linux環境下,查看由g++編譯器編譯后所形成的符號表查看函數符號名的變化,如下圖。
在這里插入圖片描述
此時C++中的函數,已經不再是單純的Swap,而是在Swap前后增加了新東西。那一前一后的東西需要查看對應編譯器的命名規則,如下。

C++的函數符號名命名規則:

  • 每個編譯器都有自己的函數名修飾規則
  • g++編譯器中的函數修飾后變成【_Z+函數長度+函數名+類型首字母
  • Windows下名字修飾規則在這里插入圖片描述

根據命名規則我們可以得出交換函數Swap在C++形成_Z4SwapPiS_代表著:

  • _Z:固定開頭
  • 4:代表著函數名字的長度,Swap長度4個字符,所以是4
  • Swap:代表了函數名
  • Pi:代表了int*類型的首字母合體,P代表是指針,i代表是整形。

在這里插入圖片描述

void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}
void f(int a, double b, char c) {cout << "f(int a, double b, char c)" << endl;}
int main()
{f(10, 'a');f('a', 10);f(10, 2.5, 'a');return 0;
}

我們使用g++編譯器,生成符號表查看上面函數f的符號名,如下圖
在這里插入圖片描述
第一個函數f:后面的類型是ic,對應形參中的intchar
第二個函數f:后面的類型是ci,對應形參中的charint
第三個函數f:后面的類型是idc,對應形參中的intdoublechar

通過這里就理解了C語言沒辦法支持重載,因為同名函數沒辦法區分。而C++是通過函數修飾規則來區分,只要參數不同,修飾出來的名字就不一樣,就支持了重載。

有此,我們可以總結出,函數的重載只會與形參列表 中的 參數個數類型類型順序相關,因為只有這些才控制著函數符號名。當函數的符號名相同時,編譯器在鏈接時候也是會區分不開,所以必須保證函數符號名唯一


五、C++98關鍵字

C++總計63個關鍵字(其中包含C語言32個關鍵字),如下表格

asmdoifreturntrycontinue
autodoubleinlineshorttypedeffor
booldynamic_castintsignedtypeidpublic
breakelselongsizeoftypenamethrow
caseenummutablestaticunionwchar_t
catchexplicitnamespacestatic_castunsigneddefault
charexportnewstructusingfriend
classexternoperatorswitchvirtualregister
constfalseprivatetemplatevoidtrue
const_castfloatprotectedthisvolatilewhile
deletegotoreinterpret_cast

ps:點我跳轉下集

以上就是本章所有內容。若有勘誤請私信不才。萬分感激💖💖 如果對大家有用的話,就請多多為我點贊收藏吧~~~💖💖
請添加圖片描述

ps:表情包來自網絡,侵刪🌹

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64529.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64529.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64529.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CGAL windows 安裝教程

1.下載源代碼 CGAL官網下載https://github.com/CGAL/cgal/releases 2.下載boost庫 BOOST官網下載https://www.boost.org/ 3.下載 GMP and MPFR 4.配置VS2022 頭文件&#xff1a; 庫路徑 做完以上步驟&#xff0c;可以使用CGAL了&#xff01;

從0入門自主空中機器人-2-2【無人機硬件選型-PX4篇】

1. 常用資料以及官方網站 無人機飛控PX4用戶使用手冊&#xff08;無人機基本設置、地面站使用教程、軟硬件搭建等&#xff09;&#xff1a;https://docs.px4.io/main/en/ PX4固件開源地址&#xff1a;https://github.com/PX4/PX4-Autopilot 飛控硬件、數傳模塊、GPS、分電板等…

每天40分玩轉Django:Django緩存

一、Django緩存概述 在高并發的Web應用中,緩存是提高性能的重要手段。通過緩存頻繁訪問的數據,可以顯著減少數據庫查詢和渲染模板的時間,從而加快響應速度,提升用戶體驗。Django提供了多層級的緩存方案,可以靈活地滿足不同場景下的緩存需求。 Django支持的緩存方式包括: 視圖…

GraphRAG 框架哪家強?選擇最適合你智能問答系統的框架

GraphRAG 框架哪家強&#xff1f;選擇最適合你智能問答系統的框架 點擊進入&#xff1a;GraphRAG系列文章-Nano-GraphRAG&#xff1a;打造輕量級醫療診斷助手 點擊進入&#xff1a;GraphRAG系列文章-突破傳統知識管理瓶頸&#xff1a;LlamaIndex GraphRAG 讓企業知識問答更智能…

Mac電腦python多版本環境安裝與切換

我當前是python3.9.6環境&#xff0c;需要使用3.9.8環境&#xff0c;通過brew安裝3.9.8版本&#xff0c;然后通過pyenv切換環境 步驟 1: 安裝 pyenv brew install pyenv brew install pyenv-virtualenv 步驟 2: 安裝 Python 3.9.8&#xff08;使用 pyenv 安裝指定版本的 Pyth…

Redis--持久化策略(AOF與RDB)

持久化策略&#xff08;AOF與RDB&#xff09; 持久化Redis如何實現數據不丟失&#xff1f;RDB 快照是如何實現的呢&#xff1f;執行時機RDB原理執行快照時&#xff0c;數據能被修改嗎&#xff1f; AOF持久化是怎么實現的&#xff1f;AOF原理三種寫回策略AOF重寫機制 RDB和AOF合…

C高級:思維導圖Day2

目錄 總覽1 總覽2 總覽1 壓縮與解壓縮 打包與解包 軟連接與硬鏈接 ubuntu下關機與重啟指令 總覽2 結束

pwntools用法

pwntools 是一個Python庫&#xff0c; 用于編寫二進制漏洞利用&#xff08;exploitation&#xff09;腳本 功能&#xff1a; 遠程連接和本地連接&#xff1a; 支持通過TCP/UDP連接遠程服務或與本地進程進行交互。Shellcode和ROP鏈構造&#xff1a; 提供了便捷的工具來生成和利…

【每日學點鴻蒙知識】placement設置top、組件攜帶自定義參數、主動隱藏輸入框、Web設置字體、對話框設置全屏寬

1、popup組件placement設置top沒有生效&#xff1f; 可以用offset屬性將popup往下邊偏移一下 來規避 2、組件攜帶自定義參數的接口是哪個&#xff1f; 參考鏈接&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-universal-attributes-…

PyTorch快速入門教程【小土堆】之優化器

視頻地址優化器&#xff08;一&#xff09;_嗶哩嗶哩_bilibili import torch import torchvision from torch import nn from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential from torch.utils.data import DataLoaderdataset torchvision.datasets.CIFAR1…

數據庫篇:mysql內置函數

前言 sql 是程序開發員繞不開的一項技能&#xff0c;而mysql是當前最流行的數據庫&#xff0c;熟知其內置的一些函數&#xff0c;可以使我們平時的開發工作更加順暢和方便 時間日期函數 字符串函數 數學計算相關函數 條件判斷函數 加密和壓縮函數 聚合函數 格式或類型轉…

C# 中 Webclient和Httpclient

在C#中&#xff0c;WebClient和HttpClient&#xff0c;這兩個類都是用于發起HTTP請求的客戶端&#xff0c;它們在使用API上傳文件或數據時有不同的優缺點和應用場景。在C#中WebClient是一種較早的網絡客戶端&#xff0c;而HttpClient是后期提供的更現代的、功能更強大的HTTP客戶…

權限獲得第一步

權限獲得第一步 下載打開附件 給了一串加密的密文 一般都是用MD5加密&#xff0c;每一段分別解碼一下 第一段不行&#xff0c;試一下第二段 這里發現第二段可以解碼出來&#xff0c;這應該就是密碼了 flag{3617656}

HTML 輪播圖(Carousel)詳細講解

HTML 輪播圖&#xff08;Carousel&#xff09;詳細講解 輪播圖&#xff08;Carousel&#xff09;是一種常見的用戶界面組件&#xff0c;用于在同一位置展示多個圖像或內容&#xff0c;允許用戶通過滑動或自動播放的方式查看不同的內容。它通常用于展示產品、圖片、廣告等。 1…

25秋招面試總結

秋招從八月底開始&#xff0c;陸陸續續面試了不少&#xff0c;現在也是已經塵埃落定&#xff0c;在這里做一些總結一些我個人的面試經歷 騰訊 騰訊是我最早面試的一家&#xff0c;一開始撈我面試的是數字人民幣&#xff0c;安全方向的崗位&#xff0c;屬于騰訊金融科技這塊。…

一份關于 Ubuntu 系統下代理配置的故障排查筆記

Ubuntu 網絡代理配置與故障排查指南 在使用 Ubuntu 系統時&#xff0c;配置網絡代理可以幫助提升網絡訪問速度或突破網絡限制。然而&#xff0c;代理配置過程中可能會遇到各種問題。本文將詳細介紹如何在 Ubuntu 下配置網絡代理&#xff0c;并提供故障排查的步驟和解決方案。 …

001__VMware軟件和ubuntu系統安裝(鏡像)

[ 基本難度系數 ]:★☆☆☆☆ 一、Vmware軟件和Ubuntu系統說明&#xff1a; a、Vmware軟件的說明&#xff1a; 官網&#xff1a; 歷史版本&#xff1a; 如何下載&#xff1f; b、Ubuntu系統的說明&#xff1a; 4、linux系統的其他版本&#xff1a;紅旗(redhat)、dibian、cent…

fiscoBcos中webase平臺導出java項目

導出合約為java項目并調用 1&#xff0e; 在webase管理平臺上面進行項目的導出 2.將下載好的項目解壓并用idea打開&#xff0c;目錄結構如下 在resources目錄下的abi放的是編譯過后的合約方法&#xff0c;bin.ecc放的是以編譯過后的智能合約&#xff0c;conf文件夾下面放的是鏈…

【嵌入式C語言】指針數組結構體

指針與數組 指針與數組指針數組數組指針 多維數組數組名的保存 結構體定義結構體定義結構體變量使用typedef簡化結構體聲明訪問結構體成員結構體內存分配字節對齊位域定義位域位域的限制示例 指針與數組 指針數組和數組指針是兩個不同的概念&#xff0c;它們涉及到指針和數組的…

Junit4單元測試快速上手

文章目錄 POM依賴引入業務層測試代碼Web層測試代碼生成測試類文件 在工作中我用的最多的單元測試框架是Junit4。通常在寫DAO、Service、Web層代碼的時候都會進行單元測試&#xff0c;方便后續編碼&#xff0c;前端甩鍋。 POM依賴引入 <dependency><groupId>org.spr…