從零開始搞定類與對象(中)

運算符重載

  • 1.當運算符被用于類類型的對象時,C++語言允許我們通過運算符重載的形式指定新的含義。C++規定類類型對象使用運算符時,必須轉換成調用對應運算符重載,若沒有對應的運算符重載,則會編譯報錯。
  • 2.?運算符重載是具有特殊名字的函數,他的名字是由operator和后面要定義的運算符共同構成。和其他函數一樣,它也具有其返回類型和參數列表以及函數體
  • 3.?重載運算符函數的參數個數和該運算符作用的運算對象數量一樣多。一元運算符有一個參數,二元運算符有兩個參數,二元運算符的左側運算對象傳給第一個參數,右側運算對象傳給第二個參數。
  • 4.如果一個重載運算符函數是成員函數,則它的第一個運算對象默認傳給隱式的this指針,因此運算符重載作為成員函數時,參數比運算對象少一個。
  • 5.運算符重載以后,其優先級和結合性與對應的內置類型運算符保持一致
  • 6.不能通過連接語法中沒有的符號來創建新的操作符:比如operator@。7.
  • 7. .*? ? ?::? sizeof? ??:? ? . 注意以上5個運算符不能重載。(選擇題里面常考,大家要記一下)
  • 8.重載操作符至少有一個類類型參數,不能通過運算符重載改變內置類型對象的含義,如:int operator+(int x, int y)
  • 9. 一個類需要重載哪些運算符,是看哪些運算符重載后有意義,比如Date類重載operator-就有意義,但是重載operator*就沒有意義。
  • 10.重載++運算符時,有前置++和后置++,運算符重載函數名都是operator++,無法很好的區分。C++規定,后置++重載時,增加一個int形參,跟前置++構成函數重載,方便區分
  • 11.重載<<和>>時,需要重載為全局函數,因為重載為成員函數,this指針默認搶占了第一個形參位置,第一個形參位置是左側運算對象,調用時就變成了對象<<cout,不符合使用習慣和可讀性。重載為全局函數把ostream/istream放到第一個形參位置就可以了,第二個形參位置當類類型對象。

?如代碼,自定義類型進行使用“==”操作符會產生報錯:

由于自定義類型比較復雜,所以默認情況下自定義類型是無法進行運算的,但是呢,有的自定義類型進行相關運算卻是有意義的,比如我們經常遇到的日期類,兩個日期相減得到的就是兩個日期之間相隔的天數,日期加上天數就能得到另一個日期,學習運算符重載,我們可以讓自定義類型進行運算,這樣會更加方便。

話不多說,我們直接來看代碼吧:

先寫好日期類的代碼,這是我們這一小節經常需要使用的類:

//日期類
#include<iostream>
using namespace std;
class Date
{
public:
//默認構造函數Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}
//在寫運算符重載的算法中,我們不可避免的會用到類中的成員變量,所以需要將成員變量改為公有的,但其實我們一般不推薦這么做,在以后我們學習了友元函數就有更好地解決辦法
//private:int _year;int _month;int _day;
};

現在,我們要對“==”運算符進行重載,也就是比較兩個日期是否相同,按照運算符重載的特點:

//重載運算符名字:由operator和后面要定義的運算符共同構成
//具有返回值,參數,函數體
bool operator==(Date x1 ,Date x2)
{//將自定義類型的比較轉化為成員變量中內置類型的比較return ((x1._year == x2._year) && (x1._month == x2._month) && (x1._day == x2._day));
}

寫完這個代碼后,再看是否還會有語法錯誤:

可以看到,當再次使用這個運算符時,就不會產生報錯了。

另外,我們可以想一下上面那個運算符重載的代碼還有啥可以改進的地方。我們在前面一節介紹過了,自定義類型的傳值傳參會調用拷貝構造,但是傳引用傳參就不會調用拷貝構造,所以在C++中,為了提高程序的性能,我們要習慣去使用引用傳參:

//引用傳參不需要調用拷貝構造
bool operator==(const Date& x1, const Date& x2)
{return ((x1._year == x2._year) && (x1._month == x2._month) && (x1._day == x2._day));
}

?那我們應當如何使用重載后的運算符呢?

方法一:函數調用的形式

bool ret= operator==( d1 , d2 );

方法二:就像內置類型一樣直接使用運算符,一般情況下我們推薦這種寫法

d1==d2;

現在我們就來運用一下這個運算符:

#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}int _year;int _month;int _day;
};//引用傳參不需要調用拷貝構造
bool operator==(const Date& x1, const Date& x2)
{return ((x1._year == x2._year) && (x1._month == x2._month) && (x1._day == x2._day));
}
int main()
{Date d1(2025, 8, 3);Date d2(2025, 8, 8);if (d1 == d2){cout << "兩個日期相同" << endl;}else{cout << "兩個日期不同" << endl;}return 0;
}

另外,為了在運算符重載中能夠使用類里面的成員變量,我們將成員變量改為了公有的,但其實這種方式不太好,一種解決方法就是將運算符重載函數寫到類里面去,我們來試一下:

#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}bool operator==(const Date& x1, const Date& x2){return ((x1._year == x2._year) && (x1._month == x2._month) && (x1._day == x2._day));}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;};//引用傳參不需要調用拷貝構造int main()
{Date d1(2025, 8, 3);Date d2(2025, 8, 8);return 0;
}

但是編譯器會報錯:

為啥就只是把運算符重載函數改到類里面就報錯了呢?

這就是this指針在裝神弄鬼了。表面上我們把函數寫到類里面去是傳遞了兩個參數,其實第一個參數的位置還有一個隱含的this指針。所以其實你是傳遞了3個參數的,但“==”只能接受2個操作數,所以會報錯。

還需注意的是,在 C++ 中,當運算符重載函數作為成員函數定義在類內部時,this?指針指向的是運算符左側的操作數對象的地址。這是運算符重載的核心規則之一。(這也就是第4點的意思)

所以,我們在類里面規定運算符重載時,我們自己寫的參數個數應該比運算符實際能接受的操作數個數少一,比如,上面的代碼應該改成:

#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
//編譯器會把它處理為:operator(Date*this,const Date& x2)bool operator==(const Date& x2){return ((_year == x2._year) && (_month == _month) && (_day == x2._day));}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;};//引用傳參不需要調用拷貝構造int main()
{Date d1(2025, 8, 3);Date d2(2025, 8, 8);d1 == d2;//等價于:d1.operator==(d2);if (d1 == d2){cout << "兩個日期相同" << endl;}else{cout << "兩個日期不同" << endl;}return 0;
}

?.*? ? ?::? sizeof? ??:? ? . 5個運算符不能重載,我們現在來簡單講一下.*運算符的用法(這個運算符的挺少用的,簡單看一下就好),見以下代碼和注釋:

//成員函數指針的創建與訪問:
#include<iostream>
using namespace std;
void func1()
{cout << "void func1()" << endl;
}
class A
{
public:void func2(){cout << "void func2()" << endl;}
};int main()
{//普通函數指針的創建:void (*pf1)() = func1;//利用函數指針來調用函數:(*pf1)();//類的成員函數指針的創建:void(A:: * pf2)() =& A::func2;//為啥類的成員函數指針要這樣寫://在 C++ 中,類成員函數指針的聲明和賦值需要特殊語法,這是由成員函數的本質特性決定的//成員函數(非靜態)與普通函數不同,它隱含一個 this 指針參數(用于訪問對象實例的數據)// 因此,成員函數指針的語法需要體現:所屬類(A::),調用時的對象綁定(通過 .* 或 ->* 運算符)//成員函數指針的調用
//想一下,利用成員函數的指針調用成員函數可以這么調用嘛:(*pf2)();//不可以的:因為成員函數中是有隱含的this指針的,this指針接收的是調用函數的對象的地址,所以在調用成員函數//時,還需要指定對象A aa;//利用成員函數指針調用函數:(aa.*pf2)();//這就是.*運算符的用途return 0;
}

再來講解一下特點8是啥意思:

重載操作符至少有一個類類型參數:意思是當你重載一個運算符(如?+,?==,?<<?等)時,至少有一個參數必須是自定義的類(class)或結構體(struct)類型,而不能全部是基本類型(如?int,?double,?char?等)。

這是因為:

  • C++ 不允許你修改基本類型(如?int,?float?等)的運算符行為,否則會導致代碼混亂。

  • 運算符重載的目的是為了讓自定義類型(如?Date,?String,?Vector?等)也能像內置類型一樣使用運算符。

?不能通過運算符重載改變內置類型對象的含義:意思是?你不能改變基本類型(如?int,?float,?char?等)的運算符的原始行為。

這是因為:

  • 如果允許修改基本類型的運算符行為,比如讓?1 + 1?返回?3,那代碼會變得極其混亂,無法維護。

  • C++ 只允許你為自定義類型(如?Date,?String)定義新的運算符行為,而不能篡改內置類型的運算規則。

?賦值運算符重載

賦值運算符重載是一個默認成員函數,用于完成兩個已經存在的對象直接的拷貝賦值,這里要注意跟拷貝構造區分,拷貝構造用于一個對象拷貝初始化給另一個要創建的對象。

賦值運算符重載的特點

1.?賦值運算符重載是一個運算符重載,規定必須重載為成員函數。賦值運算重載的參數建議寫成const 當前類類型引用,否則會傳值傳參會有拷貝
2.?有返回值,且建議寫成當前類類型引用,引用返回可以提高效率,有返回值目的是為了支持連續賦值場景。
3.?沒有顯式實現時,編譯器會自動生成一個默認賦值運算符重載,默認賦值運算符重載行為跟默認拷貝構造函數類似,對內置類型成員變量會完成值拷貝/淺拷貝(一個字節一個字節的拷貝),對自定義類型成員變量會調用他的賦值重載函數。
4.?像Date這樣的類成員變量全是內置類型且沒有指向什么資源,編譯器自動生成的賦值運算符重載就可以完成需要的拷貝,所以不需要我們顯示實現賦值運算符重載。像Stack這樣的類,雖然也都是內置類型,但是_a指向了資源,編譯器自動生成的賦值運算符重載完成的值拷貝/淺拷貝不符合我們的需求,所以需要我們自己實現深拷貝(對指向的資源也進行拷貝)。像MyQueue這樣的類型內部主要是自定義類型Stack成員,編譯器自動生成的賦值運算符重載會調用Stack的賦值運算符重載,也不需要我們顯示實現MyQueue的賦值運算符重載。這里還有一個小技巧,如果一個類顯示實現了析構并釋放資源,那么他就需要顯示寫賦值運算符重載,否則就不需要。?

寫代碼來理解這些特點:

#include<iostream>
using namespace std;
class Date
{
public://構造函數Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//拷貝構造:Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//賦值運算符重載:如果是傳值傳參,在調用賦值運算符重載時還會調用拷貝構造//但這里是傳引用傳參,不會調用拷貝構造void operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;};//引用傳參不需要調用拷貝構造int main()
{Date d1(2025, 8, 3);
//拷貝構造Date d2(d1);//賦值構造Date d3(2025, 7, 8);d3 = d1;d1.Print();d2.Print();d3.Print();return 0;
}

在調試過程中,確實調用了賦值運算符重載:?

?還需要區分一個點,如果在main函數中有這樣一行代碼:

Date d4 = d1;

請問這個代碼是會調用拷貝構造還是賦值運算符重載?

答案是賦值運算符重載,可以看到d4這個對象是在創建的時候同時讓對象d1對其進行初始化,這就是拷貝構造的另一種寫法,可能容易與拷貝構造混淆,這一點在上一節我們也是講到過的哦。

看到這里,就有一個注意的地方,我們上面寫的賦值運算符重載是有一點小小的錯誤的哦,特點2已經告訴我們了,賦值運算符重載是有返回類型的哦,這樣才能支持連續賦值。

那么我們可以想一下:如果有兩個日期類對象d1和d3,我們要執行d1=d3,那么賦值運算符重載的返回值是什么呢?返回的應當是d1中的內容,因為是要把d3賦值給d1

	//執行:d1=d3//等價于:  d1.operator(d3)//形參部分:operator=(const Date& d)//實際上,編譯器會將代碼轉化為:operator=(Date* this , const Date& d)//實參的傳參部分:d1.operator(&d1 , d3 )//函數體內部://{//   this->	_year = d._year;//   this->	_month = d._month;//	  this->_day = d._day;//}//最后返回值返回的應該是d1這個對象,而在參數中,d1這個對象的地址實際上傳給了this,所以可以通過*this獲得d1
//最終代碼:Date& operator=(const Date& d){_year =d._year;_month = d._month;_day = d._day;return *this;}
//為什么這里可以用引用返回
//原因一:因為*this并不是局部對象,*this得到的就是d1,他是在main函數中定義的,出了賦值運算符重載的作用域以后*this對應的空間并沒有被銷毀,所以這里可以傳引用返回
//原因二:如果這里是傳值返回,就要再調用拷貝構造函數,這樣比較麻煩

看到這里,其實代碼還可以再修改一下,想一下,假設有一種情況,有的小伙伴執行:d1=d1這種自己給自己賦值的代碼(雖然這種代碼無意義,但難免會有人真這么做),我們就可以把代碼改成這樣:

Date& operator=(const Date& d)
{
//當自己給自己復制時,this表示的是d1的地址,d是d1的別名,&d也就是&d1
//即this==&d1if(this!=&d){_year =d._year;_month = d._month;_day = d._day;}return *this;
}

日期類的實現

上面講了這么多,我們就一起來實踐一下,來完成日期類的實現吧!!!

//Date.h
#pragma once
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;class Date
{
public://構造函數的聲明Date(int year = 1900, int month = 1, int day = 1);//打印函數的聲明void Print();
//日期的相關比較函數bool operator<(const Date& d);bool operator<=(const Date& d);bool operator>(const Date& d);bool operator>=(const Date& d);bool operator==(const Date& d);bool operator!=(const Date& d);// d1 += 天數Date& operator+=(int day);Date operator+(int day);// d1 -= 天數Date& operator-=(int day);Date operator-(int day);// d1 - d2int operator-(const Date& d);// ++d1 -> d1.operator++()Date& operator++();// d1++ -> d1.operator++(0)// 為了區分,構成重載,給后置++,強行增加了一個int形參// 這里不需要寫形參名,因為接收值是多少不重要,也不需要用// 這個參數僅僅是為了跟前置++構成重載區分Date operator++(int);Date& operator--();Date operator--(int);//得到一月有多少天:int GetDayOfMonth(int year,int month){int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))){arr[month]++;}return arr[month];}private:int _year;int _month;int _day;
};//Date.cpp
#define  _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"
//注意:全缺省類默認構造函數的缺省參數只在聲明中寫,不在定義中寫
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}void Date::Print()
{cout << _year << '/' << _month << '/' << _day << endl;
}bool Date::operator==(const Date& d)
{return ((_year == d._year) && (_month == d._month) && (_day == d._day));
}bool Date::operator!=(const Date& d)
{return !(*this == d);
}
bool Date::operator>=(const Date& d)
{return !(*this < d);
}
bool Date::operator<=(const Date& d)
{return !(*this > d);
}
bool Date::operator< (const Date & d)
{return (_year < d._year) ||((_year == d._year) && (_month < d._month)) ||((_year == d._year) && (_month == d._month) && (_day < d._day));
}
bool Date::operator> (const Date& d)
{return (*this != d) && (!(*this < d));
}Date& Date::operator+=(int day)
{_day += day;while (_day > GetDayOfMonth(_year, _month)){_day -= GetDayOfMonth(_year, _month);_month++;if (_month == 13){_year++;_month = 1;}}return *this;
}
//不改變*this
Date Date::operator+(int day)
{Date d1 = *this;d1 += day;return d1;
}
//
//// d1 -= 天數
Date& Date:: operator-=(int day)
{if (_day > day){_day -= day;return *this;}while (_day <= day){_month--;if (_month == 0){_year--;_month = 12;}_day += GetDayOfMonth(_year, _month);if (_day > day){_day -= day;break;}}return *this;
}
Date Date::operator-(int day)
{//Date d(*this);Date d = *this;d -= day;return d;
}
////后置加加:有拷貝構造
Date Date::operator++(int)
{//Date d(*this);Date d = *this;(*this) += 1;return d;
}
//前置--
Date& Date:: operator--()
{*this -= 1;return *this;
}
Date Date::operator--(int)
{//Date d(*this);Date d = *this;(*this) -= 1;return d;
}
//前置++:沒有拷貝構造
Date& Date::operator++()
{*this += 1;return *this;
}
////
//// d1 - d2
int Date::operator-(const Date& d)
{//暴力搜索Date d1 = d;assert(*this > d);int count = 0;while (*this != d1){d1++;count++;}return count;
}// d1 += 100
//Date& Date::operator+=(int day)
//{
//	*this = *this + day;
//	return *this;
//}
//
//// d1 + 100
//Date Date::operator+(int day)
//{
//	Date tmp(*this);
//
//	tmp._day += day;
//	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
//	{
//		tmp._day -= GetMonthDay(tmp._year, tmp._month);
//		++tmp._month;
//		if (tmp._month == 13)
//		{
//			++tmp._year;
//			tmp._month = 1;
//		}
//	}
//這是+和+=的另外一套寫法,上面一種寫法是讓+去復用+=的邏輯,會經過2次復制拷貝
//這一種寫法是讓+=去復用+,會經過3次拷貝
//所以我們選用上一種方法:讓+去復用+=//test.cpp
#include"Date.h"
#include<iostream>
using namespace std;
int main()
{Date d1(2025, 1, 1);//Date d2(d1);//Date d3 = d2 + 100;//d3.Print();//d1 -= 100;//d1.Print();//Date d2 = d1 - 100;//d2.Print();/*++d1;*///d1.Print();//Date d2=d1++;//d1.Print();//d2.Print();//Date d2=d1--;//d1.Print();//d2.Print();//Date d2=--d1;//d1.Print();//d2.Print();Date d2(2024, 9, 27);Date d3 = d2 + 96;d3.Print();int gap = d1 - d2;cout << gap << endl;return 0;
}

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

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

相關文章

SpringMVC實戰指南:從環境搭建到功能實現全解析

第一章&#xff1a;SpringMVC環境搭建與基礎配置1.1 Maven依賴配置在Maven項目中&#xff0c;SpringMVC的依賴配置是開發的第一步。根據Spring官方推薦&#xff0c;以下是SpringMVC 5.3.x版本的Maven依賴配置&#xff1a;<dependencies><!-- Spring MVC核心依賴 -->…

Repo 與 manifest

Manifest&#xff1a;它本身就是一個 git 倉庫&#xff0c;其中存放的都是包含倉庫和子倉庫信息的XML文件。這些文件全部由開發者或者維護者手動配置并自己上傳到 git 倉庫。另外&#xff1a;Manifest 中的倉庫之間的依賴關系 repo 也并不關心。所以它們可以是同級的也可以是包…

深入淺出 RabbitMQ:簡單隊列實戰指南

大家好&#xff0c;我是工藤學編程 &#x1f989;一個正在努力學習的小博主&#xff0c;期待你的關注實戰代碼系列最新文章&#x1f609;C實現圖書管理系統&#xff08;Qt C GUI界面版&#xff09;SpringBoot實戰系列&#x1f437;【SpringBoot實戰系列】SpringBoot3.X 整合 Mi…

Ubuntu22-Qt Creator-fcitx-中文輸入

fcitx在ubuntu系統中路徑 /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/ /usr/lib/x86_64-linux-gnu/qt6/plugins/platforminputcontexts/ fcitx-qt5-1.2.7 編譯 下載鏈接:https://github.com/fcitx/fcitx-qt5/archive/refs/tags/1.2.7.zip Qt版本:Qt C…

【Java基礎|第十三篇】面向對象基礎(三)——繼承(一)繼承的理解,實現,特點……

&#xff08;四&#xff09;面向對象&#xff1a; 5、繼承&#xff1a; &#xff08;1&#xff09;理解&#xff1a; 概念&#xff1a; 繼承是面向對象的三大特征之一 繼承是類與類之間關系的一種&#xff08;是父類與子類的關系&#xff09; 使用場景&#xff1a; 一個類與另…

QGIS綠色版吉林一號切片體驗版插件(Jilin1Tiles)更新

吉林一號更新2024年圖源了但吉林一號切片體驗版插件&#xff08;Jilin1Tiles&#xff09;還沒有更新&#xff0c;我修改了一下代碼&#xff0c;直接集成到QGIS綠色版中。如下&#xff1a;注意&#xff1a;第一次使用的時候需要選中啟用一下插件&#xff1a;需要使用的可以直接下…

git操作命令和golang編譯腳本

git子模塊信息處理命令git init submodule git submodule updategit取消合并 git merge --abort git reset --hard HEAD{1}bat文件生成二進制set GOOSlinux set GOARCHamd64 go env -w GOFLAGS-modvendor go build -ldflags "-w -s" -ohallapiset GOOSlinux set GOAR…

通往L4之路:構建自我進化的智能駕駛決策大腦

摘要&#xff1a; 本文旨在提出一個超越當前主流“感知-預測-規劃”分離式架構的下一代自動駕駛決策系統方案。面對自動駕駛領域最核心的“長尾場景”難題&#xff0c;本文借鑒并升華了一套源于復雜策略制定的決策智能框架&#xff0c;通過構建動態駕駛世界模型&#xff08;Dyn…

AI編程助手:終結996的新希望

引言程序員工作現狀與“996”現象的普遍性AI技術快速發展對編程效率的潛在影響核心問題&#xff1a;AI IDE與AI輔助編程能否改變傳統開發模式AI IDE與AI輔助編程的核心技術AI IDE的定義與功能&#xff08;代碼補全、錯誤檢測、自動重構等&#xff09;AI輔助編程工具&#xff08…

Anthropic 禁止 OpenAI 訪問 Claude API:商業競爭與行業規范的沖突

Anthropic 禁止 OpenAI 訪問 Claude API&#xff1a;商業競爭與行業規范的沖突 文章來源&#xff1a;Poixe AI 本周&#xff0c;美國 AI 公司 Anthropic 宣布禁止 OpenAI 通過 API 訪問其 Claude 系列大模型。這一舉動引發了行業對"友好基準測試"與商業競爭邊界的熱…

區塊鏈 + 物聯網落地案例:供應鏈溯源系統開發全記錄

本文詳細記錄了區塊鏈與物聯網技術融合的供應鏈溯源系統開發全流程。從項目背景出發&#xff0c;闡述傳統供應鏈溯源痛點&#xff0c;介紹系統開發的技術架構設計&#xff0c;包括物聯網數據采集層、區塊鏈數據存儲層等核心模塊&#xff0c;詳解硬件選型、智能合約編寫、數據上…

Windows環境下Intel Fortran如何安裝配置NetCDF

NetCDF(Network Common Data Form)格式,簡稱nc格式,是一種自描述、與平臺無關的二進制數據文件,特別適合多維數據的存儲和交換,廣泛應用于氣象、海洋、地球科學等領域。本文介紹Windows環境下IntelFortran安裝配置NetCDF的過程。 一、系統環境及準備工作 1. 系統 Wind…

tcp/udp的socket特點

tcp &#xff1a; 綁定一個 socket 只是用來監聽&#xff0c;accept 對每個客戶端生成一個 socket 用來維護滑動窗口等。每個客戶端用一個 socket 用來維護滑動窗口等。 4 次揮手對應兩次 close 的 fin 和返回的 ack。 而三次揮手在 connect 里阻塞完成。 ?udp &#xff1a; 雙…

Linux命令top

top一、 命令二、 如何查看top輸出的結果一、 命令 top命令是Linux中的一個實時進程監控工具&#xff0c;類似于windows中的任務管理器。 基本命令 top二、 如何查看top輸出的結果 我們需要分析top輸出的結果 top輸出的結果分為上下兩部分&#xff0c;先看上半部分 第一行是…

Perl 數據庫連接

Perl 數據庫連接 概述 Perl是一種強大的編程語言&#xff0c;廣泛應用于文本處理、系統管理、網絡編程等領域。隨著數據庫技術的快速發展&#xff0c;Perl與數據庫的結合也日益緊密。本文將詳細介紹Perl數據庫連接的相關知識&#xff0c;包括常用的數據庫類型、連接方法以及一些…

jenkins從入門到精通-P1—九五小龐

1. jenkins的兩個核心為CI持續集成 CD持續部署2.jenkins在企業工作中的流程3. 學習的內容包括

第九節 Redis 事務、Redis 腳本

Redis 事務可以一次執行多個命令&#xff0c; 并且帶有以下兩個重要的保證&#xff1a; 事務是一個單獨的隔離操作&#xff1a;事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中&#xff0c;不會被其他客戶端發送來的命令請求所打斷。事務是一個原子操作&#x…

托福閱讀37-2

托福閱讀37-2 1.reinforcement from reintroduction定位到倒數第二句&#xff0c;這里我沒看懂former和term&#xff0c;直接懵掉了&#xff0c;然后往后看。這句話其實省略了&#xff0c;補充完應該是The former is termed reintroduction and the latter is termed reinforce…

docker-compose一鍵部署Springboot+Vue前后端分離項目

1. 背景說明 后端使用JDK8&#xff0c;前端為普通Vue項目前端訪問后端接口&#xff0c;統一帶了前綴/api 2. 項目配置 2.1 后端 yml文件里配置統一訪問前綴/api2.2 前端 API路徑配置為相對路徑&#xff1a;說明&#xff1a;我這邊前后端應用都是部署在同一臺服務器上&#xff0…

Unity_數據持久化_XML基礎

Unity數據持久化 三、XML數據持久化 3.1 XML基礎概念 3.1.1 什么是XML XML&#xff08;eXtensible Markup Language&#xff09;**是一種可擴展的標記語言&#xff0c;用于存儲和傳輸數據。它具有以下特點&#xff1a; 結構化&#xff1a;數據以層次結構組織可讀性&#xff1a;…