C++ primer 第14章 操作重載與類型轉換

文章目錄

  • 基本概念
    • 直接調用一個重載的運算符函數
    • 某些運算符不應該被重載
    • 使用與內置類型一致的含義
    • 選擇作為成員或者非成員
  • 輸入和輸出運算符
    • 重載輸出運算符<<
      • 輸出運算符盡量減少格式化操作
      • 輸入輸出運算符必須是非成員函數
    • 重載輸入運算符>>
  • 算術和關系運算符
    • 相等運算符
    • 關系運算符
  • 賦值運算符
    • 復合賦值運算符
  • 下標運算符
  • 遞增和遞減運算符
    • 區分前置和后置運算符
    • 顯式地調用后置運算符
  • 成員訪問運算符
  • 函數調用運算符
    • 含有狀態的函數對象類
    • lambda是函數對象
      • 表示lambda及相應捕獲行為的類
    • 標準庫定義的函數對象
      • 在算法中使用標準庫函數對象
      • transform函數
    • 可調用對象與function
      • 不同類型可能具有相同的調用形式
      • 重載的函數與function
  • 重載、類型轉換與運算符
    • 類型轉換運算符
      • 定義含有類型轉換運算符的類
      • 顯式的類型轉換運算符
    • 避免有二義性的類型轉換

基本概念

如果一個運算符函數是成員函數,則它的第一個(左側)運算對象綁定到隱式的this指針上,因此,成員運算符函數的(顯式)參數數量比運算符的運算對象總數少一個。

對于一個運算符函數來說,它或者是類的成員,或者至少含有一個類類型的參數:

錯誤,不能為int重定義內置的運算符
int operator+(int,int);

我們可以重載大多數運算符,但不是全部。我們只能重載已有的運算符,而無權發明新的運算符號。
在這里插入圖片描述
對于一個重載的運算符來說,其優先級和結合律與對應的內置運算符保持一致。

直接調用一個重載的運算符函數

一個非成員運算符函數的等價調用

data1+data2; //普通的表達式
operator+(data1,data2); // 等價的函數調用

調用成員運算符函數

data1+=data2; //基于“調用”的表達式
data1.operator+=(data2); // 對成員運算符函數的等價調用

某些運算符不應該被重載

通常情況下,不應該重載逗號、取地址、邏輯與、邏輯或等運算符。

使用與內置類型一致的含義

在這里插入圖片描述

選擇作為成員或者非成員

當我們定義重載的運算符時,必須首先決定是將其聲明為類的成員函數還是聲明為一個普通的非成員函數。在某些時候我們別無選擇,因為有的運算符必須作為成員;另一些情況下,運算符作為普通函數比作為成員更好。
在這里插入圖片描述

%通常定義為非成員
%=通常定義為類成員,因為它會改變對象的狀態
++通常定義為類成員,因為它會改變對象的狀態
->必須定義為類成員,否則編譯會報錯
<<通常定義為非成員
&&通常定義為非成員
==通常定義為非成員
()必須定義為類成員,否則編譯會報錯

輸入和輸出運算符

IO標準庫分別使用>>和<<執行輸入和輸出操作。對于這兩個運算符來說,IO庫定義了用其讀寫內置類型的版本,而類則需要自定義適合其對象的新版本以支持IO操作。

重載輸出運算符<<

通常情況下,輸出運算符的第一個形參是一個非常量ostream對象的引用。之所以ostream是非常量是因為向流寫入內容會改變其狀態,而該形參是引用是因為我們無法直接復制一個ostream對象。

第二個形參一般來說是一個常量的引用,該常量是我們想要打印的類類型。第二個形參是引用的原因是我們希望避免復制實參,而之所以該形參可以是常量是因為(通常情況下)打印對象不會改變對象的內容。
為了與其他輸出運算符保持一致,operator<<一般要返回它的ostream形參。

示例代碼:

ostream& operator<<(ostream&os,const Sales_data &item){//輸出內容os<<item.isbn()<<" "<<item.units_sold;//返回ostreamreturn os;
}

輸出運算符盡量減少格式化操作

用于內置類型的輸出運算符不太考慮格式化操作,尤其不會打印換行符,用戶希望類的輸出運算符也像如此行事。如果運算符打印了換行符,則用戶就無法在對象的同一行內接著打印一些描述性的文本了。相反,令輸出運算符盡量減少格式化操作可以使用戶有權控制輸出的細節。

輸入輸出運算符必須是非成員函數

與iostream標準庫兼容的輸入輸出運算符必須是普通的非成員函數,而不能是類的成員函數。否則,它們的左側運算對象將是我們的類的一個對象:

Sales_data data;
data<<cout; //如果operator<<是Sales_data的成員

因此,如果我們希望為類自定義IO運算符,則必須將其定義為非成員函數。IO運算符通常需要讀寫類的非公有數據成員,所以IO運算符一般被聲明為友元。

重載輸入運算符>>

通常情況下,輸入運算符的第一個形參是運算符將要讀取的流的引用,第二個形參是將要讀入到的(非常量)對象的引用。該運算符通常會返回某個給定流的引用。 第二個形參之所以必須是個非常量是因為輸入運算符本身的目的就是將數據讀入到這個對象中。

輸入運算符必須處理輸入可能失敗的情況,而輸出運算符不需要。

輸入時的錯誤:

  • 當流含有錯誤類型的數據時讀取操作可能失敗。
  • 當讀取操作到達文件末尾或者遇到輸入流的其他錯誤時也會失敗。

通常情況下,輸入運算符只設置failbit。除此之外,設置eofbit表示文件耗盡,而設置badbit表示流被破壞。

算術和關系運算符

通常,我們把算術和關系運算符定義成非成員函數以允許對左側或右側的運算對象進行轉換。因為這些運算符一般不需要改變運算對象的狀態,所以形參都是常量的引用。

算術運算符通常會計算它的兩個運算對象并得到一個新值,這個值有別于任意一個運算對象,常常位于一個局部變量之內,操作完成后返回該局部變量的副本作為其結果。如果類定義了算術運算符,則它一般也會定義一個對應的復合賦值運算符。此時最有效的方式是使用復合賦值來定義算術運算符:

Sales_data operator+(const Sales_data &lhs,const Sales_data &rhs){Sales_data sum = lhs;//把lhs的數據成員拷貝給sumsum+=rhs; //使用復合賦值運算符將rhs加到sum中return sum;
}

如果類同時定義了算術運算符和相關的復合賦值運算符,則通常情況下應該使用復合賦值來實現算術運算符。

相等運算符

通常情況下,c++中的類通過定義相等運算符來檢驗兩個對象是否相等。也就是說,它們會比較對象的每一個數據成員,只有當所有對應的成員都相等時才認為兩個對象相等。

關系運算符

定義了相等運算符的類也常常(但不總是)包括關系運算符。特別是,因為關聯容器和一些算法要用到小于運算符,所以定義operator<會比較有用。

通常情況下,關系運算符應該:

  • 定義順序關系,令其與關聯容器中對關鍵字的要求一致。
  • 如果類同時也含有 == 運算符的話,則定義一種關系令其與 == 保持一致。特別是,如果兩個對象是 != 的,那么一個對象應該 < 另外一個。

如果存在唯一一種邏輯可靠的 < 定義,則應該考慮為這個類定義 < 運算符。如果類同時還包含 == ,則當且僅當 < 的定義和 == 產生的結果一致時才定義 < 運算符。

賦值運算符

我們可以重載賦值運算符,不論形參的類型是什么,賦值運算符都必須定義為成員函數。

示例代碼:
在這里插入圖片描述

復合賦值運算符

復合賦值運算符不非得是類的成員,不過我們還是傾向于把包括復合賦值在內的所有賦值運算都定義在類的內部。為了與內置類型的復合賦值保持一致,類中的復合賦值運算符也要返回其左側運算對象的引用。

示例代碼:
在這里插入圖片描述
賦值運算符必須定義成類的成員,復合賦值運算符通常情況下也應該這樣做。這兩類運算符都應該返回左側運算對象的引用。

下標運算符

表示容器的類通常可以通過元素在容器中的位置訪問元素,這些類一般會定義下標運算符operator[ ]。

下標運算符必須是成員函數。

為了與下標的原始定義兼容,下標運算符通常以所訪問元素的引用作為返回值,這樣做的好處是下標可以出現在賦值運算符的任意一端。進一步,我們最好同時定義下標運算符的常量版本和非常量版本,當作用于一個常量對象時,下標運算符返回常量引用以確保我們不會給返回的對象賦值

示例代碼:
在這里插入圖片描述

遞增和遞減運算符

定義遞增和遞減運算符的類應該同時定義前置版本和后置版本。這些運算符通常應該被定義成類的成員。

為了與內置版本保持一致,前置運算符應該返回遞增或遞減后對象的引用。
在這里插入圖片描述
在這里插入圖片描述

區分前置和后置運算符

前置和后置版本使用的是同一個符號,意味著其重載版本所用的名字將是相同的,并且運算對象的數量和類型也相同。為了解決這個問題,后置版本接受一個額外的(不被使用的)int類型的形參。當我們使用后置運算符時,編譯器為這個形參提供一個值為0的實參。盡管從語法上來說,后置函數可以使用這個額外的形參,但是在實際過程中通常不會這么做。這個形參的唯一作用就是區分前置版本和后置版本的函數,而不是真的要在實現后置版本時參與運算。

為了與內置版本保持一致,后置運算符應該返回對象的原值(遞增或遞減之前的值),返回的形式是一個值而非引用。

后置版本示例代碼:
在這里插入圖片描述

顯式地調用后置運算符

StrBlobPtr p(a1);
p.operator++(0);  //調用后置版本的operator++
p.operator++();   //調用前置版本的operator++

成員訪問運算符

箭頭運算符 -> 必須是類的成員。解引用運算符 * 通常也是類的成員。

重載的箭頭運算符必須返回類的指針或者自定義了箭頭運算符的某個類的對象。

函數調用運算符

如果類重載了函數調用運算符,則我們可以像使用函數一樣使用該類的對象。因為這樣的類同時也能存儲狀態,所以與普通函數相比它們更加靈活。

函數調用運算符必須是成員函數,一個類可以定義多個不同版本的調用運算符,相互之間應該在參數數量或類型上有所區別。

如果類定義了調用運算符,則該類的對象稱作函數對象。因為可以調用這種對象,所以我們說這些對象的“行為像函數一樣”。

class absInt{int operator()(int val)const{return val < 0 ? -val : val;}
}int i=-42;
absInt absObj;		//含有函數調用運算符的對象
int ui = absObj(i);  //將i傳遞給absObj.operator()

即使absObj只是一個對象而非函數,我們也能“調用”該對象。調用對象實際上是在運行重載的調用運算符。該例中,該運算符接受一個int值并返回其絕對值。

含有狀態的函數對象類

和其他類一樣,函數對象類除了operator()之外也可以包含其他成員。函數對象類通常含有一些數據成員,這些成員被用于定制調用運算符中的操作。

示例代碼:

#ifndef PRINTSTRING_H
#define PRINTSTRING_H#include<iostream>
#include<string>
using namespace std;class PrintString
{
public:PrintString(ostream &o=cout,char c=' ') :os(o),sep(c){}void operator()(const string &s)const { os << s << sep; }
private:ostream &os;char sep;
};
#endif

測試代碼:

void testPrintString() {PrintString p1;p1("hello");PrintString p2(cout, '!');p2("hello");
}

輸出結果:

hello hello!

示例代碼:

//IntCompare類
class IntCompare {
public:IntCompare(int v) :val(v) {}bool operator()(int v) { return val == v; }
private:int val;
};//測試代碼vector<int>vec = { 1,2,3,2,1 };int oldVal = 2;int newVal = 200;IntCompare icmp(oldVal);replace_if(vec.begin(),vec.end(),icmp,newVal);for (auto a:vec) {cout << a << " ";}

輸出結果:

1 200 3 200 1

lambda是函數對象

在lambda表達式產生的類中含有一個重載的函數調用運算符,例如:

[](const string & a , const string & b){return a.size()<b.size();}

其行為類似于下面這個類的一個未命名對象:

class ShortString{
public:bool operator()(const string & a , const string & b)		{return a.size()<b.size();}
}

該類可被如下調用:

stable_sort(words.begin(),words.end(),ShortString());

當stable_sort內部的代碼每次比較兩個string時就會“調用”這一對象,此時該對象將調用運算符的函數體,判斷第一個string的大小小于第二個時返回true。

表示lambda及相應捕獲行為的類

當一個lambda表達式通過引用捕獲變量時,將由程序負責確保lambda執行時引用所引的對象確實存在。因此編譯器可以直接使用該引用而無須在lambda產生的類中將其存儲為數據成員。

如果通過值捕獲的變量被拷貝到lambda中,這種lambda產生的類必須為每個值捕獲的變量建立對應的數據成員,同時創建構造函數,令其使用捕獲的變量的值來初始化數據成員。

示例如下:

[sz](const string & a){return a.size()>=sz;}

該lambda表達式產生的類將形如:

class SizeComp{
public:SizeComp(size_t n):sz(n){}  //該形參對應捕獲的變量//該調用運算符的返回類型、形參和函數體都與lambda一致bool operator(){const string & s}const{return s.size()>=sz;}
private:size_t sz;//該數據成員對應通過值捕獲的變量
}

這個類含有一個數據成員以及一個用于初始化該成員的構造函數。這個合成的類不含有默認構造函數,因此要想使用這個類必須提供一個實參:

auto wc = find_if(words.begin(),words.end(),SizeComp(sz));

lambda表達式產生的類不含默認構造函數、賦值運算符及默認析構函數;它是否含有默認的拷貝 / 移動構造函數則通常要視捕獲的數據成員類型而定。

標準庫定義的函數對象

標準庫定義了一組表示算術運算符、關系運算符和邏輯運算符的類,每個類分別定義了一個執行命名操作的調用運算符。例如,plus類定義了一個函數調用運算符用于對一對運算對象執行+的操作;modulus類定義了一個調用運算符執行二元的%操作;equal_to類執行==。
示例代碼

	plus<int>intAdd;negate<int>intNegate;//negate<int>可對int取反int sum = intAdd(10,20);cout << sum << endl;sum = intNegate(intAdd(10, 20));cout << sum << endl;sum = intAdd(10, intNegate(20));cout << sum << endl;

輸出結果:

30
-30
-10

標準庫函數對象,下表所列的類型定義在functional頭文件中
在這里插入圖片描述

在算法中使用標準庫函數對象

表示運算符的函數對象常用來替換算法中的默認運算符。例如,默認情況下,排序算法使用operator<將序列按照升序排列,如果要執行降序排列的話,我們可以傳入一個greater類型的對象。該類將產生一個調用運算符并負責執行待排序類型的大于運算。例如,如果svec是一個vector<string>

sort(svec.begin(),svec.end(),greater<string>());

示例代碼:

	vector<int>vec{ 1,3,5,7,9,2,4,6,8,10 };//統計大于4的值有多少個int num = count_if(vec.begin(),vec.end(),bind2nd(greater<int>(),4));cout << num << endl;vector<string>sv{"hello","hello","hi","nihao","nihao"};//找到第一個不等于hello的字符串auto its = find_if(sv.begin(),sv.end(), bind2nd(not_equal_to<string>(), "hello"));cout << *its << endl;//將所有的值乘以2transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies<int>(), 2));for (auto a:vec) {cout << a << " ";}cout << endl;

輸出結果:

6
hi
2 6 10 14 18 4 8 12 16 20

transform函數

transform函數的作用是:將某操作應用于指定范圍的每個元素。transform函數有兩個重載版本:

transform(first,last,result,op);
first是容器的首迭代器,last為容器的末迭代器,result為存放結果的容器,op為要進行操作的一元函數對象或sturct、class。

transform(first1,last1,first2,result,binary_op);
first1是第一個容器的首迭代 器,last1為第一個容器的末迭代器,first2為第二個容器的首迭代器,result為存放結果的容器,binary_op為要進行操作的二元函數 對象或sturct、class。

可調用對象與function

c++語言中有幾種可調用的對象:函數、函數指針、lambda表達式、bind創建的對象以及重載了函數調用運算符的類。

和其他對象一樣,可調用的對象也有類型。例如,每個lambda有它自己唯一的(未命名)類類型;函數及函數指針的類型則由其返回值類型和實參類型決定,等等。

不同類型可能具有相同的調用形式

在這里插入圖片描述
上面這些可調用對象分別對其參數執行了不同的算術運算。盡管它們的類型各不相同,但是共享同一種調用形式:int(int,int)

我們可以定義一個函數表用于存儲指向這些可調用對象的“指針”。當程序需要執行某個特定的操作時,從表中查找該調用的函數。

函數表可以很容易的通過map來實現。我們的map可以定義成如下形式:

//構建從運算符到函數指針的映射關系,其中函數接受兩個int、返回一個int
map<string,int(*)(int,int)>binops;

我們可以按照下面的形式將add的指針添加到binops中:

binops.insert({"+",add});//{"+",add}是一個pair

但是我們不能將mod或者divide存入binops中,因為mod是個lambda表達式,而每個lambda有它自己的類類型,該類型于存儲在binops中的類型不匹配。

binops.insert({"%",mod});//錯誤:mod不是一個函數指針

我們可以使用一個名為function的新的標準庫類型解決上述問題,function定義在functional頭文件中,下表列出了function定義的操作:
在這里插入圖片描述
function是一個模板,和我們使用過的其他模板一樣,當創建一個具體的function類型時我們必須提供額外的信息。示例如下:

function<int(int,int)>

在這里我們聲明了一個function類型,它可以表示接受兩個int、返回一個int的可調用對象。

function<int(int,int)>f1 = add;
function<int(int,int)>f1 = divide();
function<int(int,int)>f1 = [](int i,int j){return i*j};//f1(4,2): 6
//f2(4,2): 2
//f3(4,2): 8

使用這個function我們可以重新定義map:

map<string,function<int(int,int)>>binops;

我們能把所有可調用對象,包括函數指針、lambda或者函數對象在內,都添加到這個map中:

map<string,function<int(int,int)>>binops={
{"+",add}, 					 		 //函數指針
{"-",std::minus<int>()}, 			 //標準庫函數對象
{"/",divide()},						 //用戶定義的函數對象
{"*",[](int i,int j){return i*j}},	 //未命名的lambda
{"%",mod},							 //命名的lambda
}

調用操作:

binops["+"](10,5); //調用add(10,5)

重載的函數與function

我們不能(直接)將重載函數的名字存入function類型的對象中。
在這里插入圖片描述

重載、類型轉換與運算符

類型轉換運算符

類型轉換運算符是類的一種特殊成員函數,它負責將一個類類型的值轉換成其他類型。類型轉換函數的一般形式如下所示:

operator type()const;

其中type表示某種類型。類型轉換運算符可以面向任意類型(除了void之外)進行定義,只要該類型能作為函數的返回類型。因此我們不允許轉換成數組或者函數類型,但允許轉換成指針(包括數組指針及函數指針)或者引用類型。

一個類型轉換函數必須是類的成員函數;它不能聲明返回類型,形參列表也必須為空。類型轉換函數通常應該是const。

定義含有類型轉換運算符的類

class SmallInt {
public:SmallInt(int i = 0) :val(i) {}operator int()const { return val; }void print() { cout << val << endl; }
private:size_t val;
};//測試代碼:SmallInt s1;s1 = 4;s1.print();cout << s1 + 5 << endl;s1 = 3.5;s1.print();cout << s1 + 5 << endl;

輸出結果:

4
9
3
8

因為類型轉換運算符是隱式執行的,所以無法給這些函數傳遞實參,當然也就不能在類型轉換運算符的定義中使用任何形參。同時,盡管類型轉換函數不負責指定返回類型,但實際上每個類型轉換函數都會返回一個對應類型的值:
在這里插入圖片描述

顯式的類型轉換運算符

當類型轉換運算符是顯式的時候,我們也能執行類型轉換,不過必須通過顯式的強制類型轉換才可以。

class SmallInt {
public:SmallInt(int i = 0) :val(i) {}explicit operator int()const { return val; }void print() { cout << val << endl; }
private:size_t val;
};//測試代碼SmallInt s1;s1 = 4;s1.print();cout << int(s1) + 5 << endl;s1 = 3.5;s1.print();cout << int(s1) + 5 << endl;

如果表達式被用作條件,則編譯器會將顯式的類型轉換自動應用于它。換句話說,當表達式出現在下列位置時,顯式的類型轉換將被隱式地執行:
在這里插入圖片描述

向bool的類型轉換通常用在條件部分,因此operator bool一般定義成explicit的。

避免有二義性的類型轉換

如果類中包含一個或多個類型轉換,則必須確保在類類型和目標類型之間只存在唯一一種轉換方式。否則的話,我們編寫的代碼很可能會具有二義性。

在兩種情況下,可能產生多重轉換路徑。

  • 兩個類提供相同的類型轉換,例如,當A類定義了一個接受B類對象的轉換構造函數,同時B類定義了一個轉換目標是A類的類型轉換運算符時,我們就說它們提供了相同的類型轉換。
    在這里插入圖片描述
  • 類定義了多個轉換規則,而這些轉換涉及的類型本身可以通過其他類型轉換聯系在一起。最典型的例子是算術運算符,對某個給定的類來說,最好只定義最多一個與算術類型有關的轉換規則。
    在這里插入圖片描述

除了顯式地向bool類型的轉換之外,我們應該盡量避免定義類型轉換函數并盡可能地限制那些“顯然正確”的非顯式構造函數。

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

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

相關文章

C語言 回調函數 produce(arr,len,getRand)

基本介紹 回調函數:形參中包含另一個函數的函數指針 用函數指針接收另一個函數 案例 代碼解析 具體代碼 #include<stdio.h> #include<stdlib.h> //回調函數--//函數原型 int getRand(); int *produce(int*arr,int len,int(*get)()); int main() {int arr[10…

從零開始配置服務器密碼機的開發環境

開發環境環境配置安裝gcc編譯器安裝g編譯器安裝make安裝cmake安裝ssh安裝git和配置安裝大文件管理工具git-lfs安裝數據庫sqlite3安裝數據庫sqlite_orm文件安裝Openssl安裝Tcl和Tk安裝tcl-expect-dev安裝boost安裝clang-format安裝Clion注意事項安裝automake和libudev-dev環境配…

C語言 動態內存分配機制(堆區) int*p=malloc(5*sizeof(4))

C程序內存分配圖 棧區:局部變量 堆區:動態分配的數據 靜態存儲區/全局區:全局變量,靜態數據 代碼區:代碼,指令 內存分配說明 內存動態分配的相關函數 堆區: #inlcude<stdlib.h> Malloc(size);//分配長度為size個字節的連續空間 Calloc(n,size);//分配size個長度為n…

C++ primer 第15章 面向對象程序設計

文章目錄前言OOP&#xff1a;概述繼承動態綁定定義基類和派生類定義基類成員函數與繼承訪問控制與繼承定義派生類派生類中的虛函數派生類對象及派生類向基類的類型轉換派生類構造函數派生類使用基類的成員繼承與靜態成員派生類的聲明被用作基類的類防止繼承的發生類型轉換與繼承…

服務器密碼機部分文件的介紹學習

相關文件包 automake,autoconf使用詳解

C語言 結構體 struct Cat cat1;

引入 使用傳統技術解決 需要定義多個變量或數組 結構體與結構體變量的關系示意圖 類似Java類中的對象(結構體)與屬性(結構體變量) 一切物體都可以看作對象(結構體) 補充:C語言數據類型 簡單使用案例 代碼 Cat是我們自己定義的數據類型 struct Cat cat1;//創建struct Cat的…

boost Filesystem Library Version 3關于文件的一些函數封裝 fsync()函數

boost boost Filesystem Library Version 3boost::filesystem使用方法,根據路徑創建文件夾使用boost.filesystem檢查文件是否存在的正確方式std::filesystem::temp_directory_path關于C#:與boost :: filesystem :: unique_path()等效的C 17是什么?C++ 檔案、資料夾、路徑處理…

c++面向對象高級編程 總目錄

本文是對學習侯捷視頻 c面向對象高級編程系列博客的目錄總索引。 c面向對象高級編程 學習一 不帶指針的類&#xff1a; 訪問私有成員變量的方式&#xff0c;內聯inline&#xff0c;常量成員函數&#xff0c;構造函數&#xff0c;值傳遞&#xff0c;引用傳遞&#xff0c;操作符…

C語言 共用體/聯合體 union

引入 傳統技術的缺陷—結構體 共用體基本介紹 共用體與結構體一樣都是值傳遞 定義共用體的三種方式 內存布局 共用體數據空間占用最大的成員的數據空間大小 案例解析 1) 2) 3) 4) 注: 1010 1101 0101 0100所對應的十進制是負數 計算機中的二進制都是以補碼存儲的,所…

C++ Makefile文件詳解

什么是Makefile文件 一個工程&#xff0c;源文件不計其數&#xff0c;按照類型、功能、模塊分別放在對應的若干個目錄中Makefile定義了一系列的規則&#xff0c;比如定義文件編譯的先后順序。類似shell腳本&#xff0c;也可以執行操作系統的命令Makefile帶來的好處是自動化編譯…

C語言 項目練習-家庭收支軟件

目標 需求說明 界面說明 登記收入界面: 登記支出界面 收支明細界面 退出界面 項目代碼改進要求 自己完成的代碼 版本1 #include<stdio.h> #include<string.h> void choose(int button,int i); //項目--家庭收支軟件 static double total10000;//總金額 #de…

c++ fmt 庫安裝和使用示例、clion配置

安裝 git clone https://github.com/fmtlib/fmt.gitmake .mkae && make install CLion使用 使用和安裝存在出入下載源碼&#xff0c;可以先 clone 到你的項目中去&#xff0c;https://github.com/fmtlib/fmt &#xff0c;我放到的是項目的 dependencies 目錄然后在…

C語言 項目 CRM系統(客戶信息管理系統)

項目目標 項目需求說明 系統界面 1)添加客戶界面 通過編號來區分客戶 2)刪除客戶界面 對用戶輸入的編號進行核查,存在與否,合法與否 3)顯示客戶列表界面 4)修改客戶信息的界面 項目設計 Customer結構體的設計 CRM系統結構框架圖 案例代碼 #include <stdio.h>…

代碼重構 防火墻 相關知識

參考 依據Linux命令以及sysconf下現有的iptables命令&#xff0c;詳見hsm_sysconf_server/src/sysconf_server.cpp中的firewall規則。 接口名稱 firewall_manager 目的(現實) 根據網口直連獲取當前eth0和eth1的各種信息保證設置的正確性 以及要針對管理口和服務口設計不…

C語言 文件的基本介紹

基本介紹 輸入流與輸出流 重點在C程序(內存)的數據移動方向 對于C程序(內存) 輸入數據:輸入流 輸出數據:輸出流 輸入 和輸出 C標準庫 標準輸入輸出庫 標準文件 getchar()&putchar()函數 代碼 #include<stdio.h> #include<stdlib.h> //文件--getchar()和…

ubuntu修改字體 樣式

使用 快捷鍵 ctrlaltt 打開終端安裝gnome-tweaks桌面管理工具 sudo apt install gnome-tweaksaltf2 在運行窗口輸入 gnome-tweaks 命令&#xff0c;然后回車打開優化窗口&#xff0c;選擇第二個front字體選項ubuntu顯示中文

C語言 文件的讀寫

引入 OS操作系統 打開文件fopen()函數 讀寫模式: r:讀取已有文件 w:文件不存在,創建文件并寫入文件.文件存在,內容清零,再寫入文件 a: 文件不存在,創建文件并寫入文件.文件存在,以追加的形式寫入文件 r:讀寫已有文件 w:文件不存在,創建文件并讀寫文件.文件存在,內容清零,再…

StarWind V2V Image Converter:虛擬機鏡像轉換工具,可將 IMG 文件轉換為 VMware VMDK 文件

操作流程 選擇本地的需要轉換的文件找到源文件的路徑&#xff0c;img格式選擇轉化后的格式 第一個選擇 第二個 速度快一些選擇將轉化后的文件的存儲路徑軟件的下載鏈接 鏈接: https://pan.baidu.com/s/1Fe6yI42Zz9d_Q7aUhGe1FQ 提取碼: 5vmv

數學建模基礎知識

原型與模型 模型的分類 數學建模 數學建模的分類 成為建模大神 數學建模比賽 數學建模一般步驟 數學建模全過程 數學建模論文寫作 1&#xff09;摘要:是決定最后獲獎等級的關鍵 2&#xff09;問題重述:使用自己的語言將問題重述一次 3&#xff09;符號說明:對于常見的或…