31 C++11

本節目標

  1. c++11簡介
  2. 列表初始化
  3. 變量類型推導
  4. 范圍for循環
  5. 新增加容器
  6. 右值
  7. 新的類功能
  8. 可變參數模板

1. c++11簡介

在2003年標準委員會提交了一份計數勘誤表(簡稱TC1),使得c++03這個名字已經取代了c++98稱為c++11之前的最新的c++標準名稱。不過由于c++03(TC1)主要是對c++98標準中的漏洞進行修復,語言的核心部分沒有改動,因此人們習慣性的把兩個標準合并稱為c++98/03標準。從c++0x到c++11,c++標準10年磨一劍,第二個真正意義上的標準姍姍來遲。相對于c++98/03,c++11則帶來了數量可觀的變化,其中包含了約140個新特性,以及對c++03標準中約600個缺陷的修正,這使得c++11更像是從c++98中孕育出來的新語言。相比較而言,c++11能更好的用于系統開發和庫開發、語法更加泛化和簡單化,更穩定和安全,不僅功能更強大,而且能提升程序員的開發效率,公司實際項目開發中也用的比較多,所以要作為一個重點去學習。c++11增加的語法特性篇幅很多,沒辦法一一講解
https://en.cppreference.com/w/cpp/11

小故事:
1998年是C++標準委員會成立的第一年,本來計劃以后每5年視實際需要更新一次標準,C++國際標準委員會在研究C++03的下一個版本的時候,一開始計劃2007年發布,所以最初這個標準叫C++07。但是到06年的時候,官方覺得2007年肯定完不成C++07,而且官方覺得2008年可能也完不成。最后干脆叫C++0x。x的意思是不知道到底能在07還是08還是09年完成。結果2010年的時候也沒完成,最后在2011年終于完成了C++標準。所以最終定名為C++11

2. 統一的列表初始化

2.1 {} 初始化

在c++98中,標準允許使用花括號{}對數組或者結構體元素進行統一的列表初始值設定。比如

struct Point
{int _x;int _y;
};int main()
{int arr1[] = { 1, 2, 3, 4, 5 };int arr2[5] = { 0 };Point p = { 1, 2 };return 0;
}

c++11擴大了用大大括號的列表(初始化列表)的使用范圍,使其可用于所有的內置類型和用戶自定義類型,使用初始化列表時,可添加等號(=),也可不添加

int x1 = 1;
int x2{ 2 };//new也可以列表初始化
int* pa = new int[4] {0};

創建對象u額可以用列表初始化方式調用構造函數初始化,但有本質區別,是先用括號的內容構造一個臨時對象,再拷貝構造給初始化對象,會優化為直接構造

class Date
{
public:Date(int year, int month, int day):_year(year), _month(month), _day(day){cout << "Date(int year, int month, int day)" << endl;}
private:int _year;int _month;int _day;
};//創建對象列表初始化
Date d1( 2022, 1 ,1 ); //舊初始化方式
Date d2{ 2022, 1, 2 };
Date d3 = { 2022, 1, 3 };//單參數構造函數支持隱士類型轉換
string str = "xxxxx";//證明,這里不能優化,所以轉不了,必須加const
const Date& d4 = { 2023, 11 , 5 };

2.2 std::initializer_list

介紹文檔
http://www.cplusplus.com/reference/initializer_list/initializer_list/

是什么類型:

 // the type of il is an initializer_list auto il = { 10, 20, 30 };cout << typeid(il).name() << endl;

在這里插入圖片描述

Date d1( 2022, 1 ,1 );
vector<int> v1 = { 0, 1, 2, 3, 4 };

可以使用迭代器遍歷

initializer_list<int> l2 = { 0, 1, 2, 3, 4 };
initializer_list<int>::iterator it = l2.begin();
while (it != l2.end())
{cout << *it << " ";it++;
}

在這里插入圖片描述

這里的v1和d1不一樣,上面的是構造的對象,下面是先構造的initializer_list類型,v1的參數個數可以是隨意的,d1只能是三個

使用場景
std::initializer_list一般是作為構造函數的參數,c++11對stl中的不少容器增加了它作為參數的構造函數,這樣初始化容器就方便多了。也可以作為operator=的參數,就可以用大括號賦值

在這里插入圖片描述
讓vector也支持{}初始化和賦值

vector(std::initializer_list<T> lt)
{Reserve(lt.size());for (auto& e : lt){PushBack(e);}
}
vector<T>& operator=(initializer_list<T> l) {vector<T> tmp(l);std::swap(_start, tmp._start);std::swap(_finish, tmp._finish);std::swap(_endofstorage, tmp._endofstorage);return *this;}

當參數的個數和構造函數匹配時會識別為對象,不匹配時會認為是initializer_list類型

3. 聲明

c++11通了多種簡化聲明的方式,尤其是在使用模板時

3.1 auto

c++98中auto是一個存儲類型的說明符,表明變了是局部自動存儲類型,但是局部域中定義局部的變量默認就是自動存儲類型,所以auto就沒什么價值了。c++11廢除auto原來用法,將其用于實現自動類型判斷,這樣要求必須顯示初始化,讓比那一期將定義對象的類型設置為初始化值的類型
typeid可以獲得變量的類型字符串

int i = 10;
auto p = i;
auto pf = strcpy;cout << typeid(p).name() << endl;
cout << typeid(pf).name() << endl;

在這里插入圖片描述

3.2 decltype

上面可以推導類型,但推導的類型不能用來創建變量,如果想根據某個變量類型推導并創建變量,可以用decltype,將變量的類型聲明為表達式指定的類型

double y = 2.2;
decltype(y) ret = 3.3;cout << typeid(ret).name() << endl;

3.3 nullptr

由于c++中NULL被定義為字面量0,這樣就可能帶來一些問題,0既指針常量,又表示整形常量。所以出于清晰和安全的角度考慮,c++11新增了nullptr,表示空指針

#ifndef NULL#ifdef __cplusplus#define NULL    0#else#define NULL    ((void *)0)#endif#endif

4.范圍for循環

5. stl一些變化

圈起來的是幾個新容器,但是實際最有用的是unordered_map和unordered_set。
在這里插入圖片描述
array和內置數組相比,越界訪問會報錯
容器的新方法
增加的新方法都用的比較少。比如提供了cbegin和cedn方法返回const迭代器等待,但意義不大,begin和end也可以返回const迭代器,屬于錦上添花的操作
插入接口函數增加了右值版本
http://www.cplusplus.com/reference/vector/vector/emplace_back/
意義在哪,說能提高效率,如何提高的

在這里插入圖片描述

6. 右值引用和移動語義

6.1 左值引用和右值引用

傳統c++語法就有引用,c++11新增了右值引用特性,無論是左值還是右值引用,都是給對象取別名

左值是一個表示數據的表達式(變量名或解引用的指針),可以獲取它的地址,可以賦值,左值可以出現在賦值符號左邊,右值不能出現在賦值符號左邊。定義時const修飾后的左值,不能賦值,但可以取地址。左值引用就是給左值的引用,取別名

int* p = new int(0);
int b = 1;
const int c = 2;//以下都是左值引用
int*& rp = p;
int& rb = b;
const int& rc = c;
int& pvalue = *p;

什么是右值,什么是右值引用
右值也是一個表示數據的表達式,如:字面常量、表達式返回值、函數返回值(這個不能是左值引用返回)等待,右值可以出現在賦值符號的右邊,不能出現在左邊,右值不能取地址。右值引用就是對右值的引用,給右值取別名

double x = 1.1, y = 2.2;
//以下是常見的右值
10;
x + y;
fmin(x, y);//以下幾個都是右值引用
int&& rr1 = 10;
double&& rr2 = x + y;
double&& rr3 = fmin(x, y);//編譯會報錯,error c2106, "=":左操作數必須為左值
10 = 1;
x + y = 1;
fmin(x, y) = 1;

6.2 左值引用和右值引用比較

左值引用總結:
1.左值引用只能引用左值,不能引用右值,但是const左值引用既可以引用左值,也可以引用右值
2.右值引用不能引用左值,move的可以

//左值引用不能給右值取別名,const左值可以
int& r1 = 10;
const int& r2 = 10;
//右值引用不能給左值取別名,move可以
int i = 10;
int&& rr3 = i;
int&& rr4 = move(i);

6.3 左值引用使用場景和意義

左值做參和返回值都可以提高效率,減少了拷貝

#pragma once
#include <string>
#include <iostream>
#include <assert.h>class string
{
public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}string(const char* str = ""):_size(strlen(str)), _capacity(_size){//cout << "string(char* str)" << endl;_str = new char[_capacity + 1];strcpy(_str, str);}// s1.swap(s2)void swap(string& s){::std::swap(_str, s._str);::std::swap(_size, s._size);::std::swap(_capacity, s._capacity);}// 拷貝構造string(const string& s):_str(nullptr){std::cout << "string(const string& s) -- 深拷貝" << std::endl;string tmp(s._str);swap(tmp);}// 賦值重載string& operator=(const string& s){std::cout << "string& operator=(string s) -- 深拷貝" << std::endl;string tmp(s);swap(tmp);return *this;}~string(){delete[] _str;_str = nullptr;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void push_back(char ch){if (_size >= _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}//string operator+=(char ch)string& operator+=(char ch){push_back(ch);return *this;}const char* c_str() const{return _str;}
private:char* _str;size_t _size;size_t _capacity; // 不包含最后做標識的\0
};

左值引用的短板
當函數返回對象是一個局部變量,除了函數作用域就不存在了,不能使用左值引用返回,只能傳值返回。例如:string to_string(int value)函數中可以看到,這里只能傳值返回,傳值返回會導致至少一次拷貝構造(如果舊一點的編譯器可能是兩次拷貝構造)

string to_string(int value)
{string ret;while (value){int x = value % 10;value /= 10;ret += '0' + x;}std::reverse(ret.begin(), ret.end());return ret;
}

舊編譯器會產生兩次拷貝構造,返回的ret對象拷貝一次,賦值的時候也會調用一次賦值重載。既然ret已經是一個要銷毀的對象了,多次拷貝就會造成資源的浪費。下面第一個是連續的構造和拷貝構造都可以優化一次拷貝構造
在這里插入圖片描述
下面這個無法優化
在這里插入圖片描述
右值引用和移動語義解決上述問題
右值可以分為:
1.純右值,內置類型右值
2.將亡值,自定義的右值
移動構造本質是將參數右值的資源竊取過來,占為己有,不做深拷貝,叫它移動構造,就是竊取別人的資源構造自己。所以可以實現拷貝和賦值的移動版本
編譯器會選擇最匹配的調用,to_string返回的是右值,如果既有拷貝又有右值,就會匹配移動構造

//移動拷貝
string(string&& s)
{std::cout << "string(string&& s) -- 移動語義" << std::endl;swap(s);
}
//移動賦值
string& operator=(string&& s)
{std::cout << "string& operator=(string s) -- 移動語義" << std::endl;swap(s);return *this;
}

在這里插入圖片描述
s和ret的字符串是同一個

運行后調用了一次移動構造和移動賦值,因為如果用一個已經存在的對象接收,編譯器沒辦法優化,to_string函數中先用str生成構造一個臨時對象,但是可以看到,編譯器把str識別成了右值,調用了移動構造,然后把臨時對象作為to_string函數調用的 返回值賦值給ret1,調用的移動賦值

stl容器都增加了移動構造和移動賦值

string s1("hello");
string s2 = s1;
string s3 = std::move(s1);

6.4 右值引用左值及一些深入的使用場景

按照語法,右值引用只能引用右值,但右值引用一定不能引用左值嗎?有些場景下,需要用右值去引用左值實現移動語義。當需要右值引用左值時,可以通過move函數將左值轉化為右值,c++11中,std::move()函數位于頭文件中,該函數名字具有迷惑性,并不搬移任何東西,唯一的功能是將一個左值強制轉換為右值使用,實現移動語義

template<class _Ty>inline typename remove_reference<_Ty>::type&& move(_Ty&& _Arg) _NOEXCEPT{// forward _Arg as movablereturn ((typename remove_reference<_Ty>::type&&)_Arg);}
//move會改為右值,s1的資源置空,轉移給了s3
string s1("hello");
string s2 = s1;
string s3 = std::move(s1);
//move的返回值是右值,并不改變變量本身
string s4 = s1;

stl容器也加入了右值引用版本
在這里插入圖片描述

std::list<string> l1;
string s1 = "hello";
//左值
l1.push_back(s1);
//右值
l1.push_back(to_string(1234));運行結果:
// string(const string& s) -- 深拷貝
// string(string&& s) -- 移動語義

在這里插入圖片描述

修改list
在前面的list中加入右值插入的版本,先把pushback函數加入右值,這時還是會有深拷貝
右值被右值引用以后得屬性是左值,編譯器設計因為右值引用需要被修改

在這里插入圖片描述
這里x傳入下層又變為了左值,需要傳給inert的右值版本move后的,insert函數里創建節點也需要再次move

__list_node(T&& x): _prev(nullptr), _next(nullptr), _data(std::move(x))
{}void push_back(T&& x)
{Insert(end(), std::move(x));
}void Insert(iterator pos, T&& x)
{node* new_node = new node(std::move(x));//記錄前后節點node* pre = pos.node_iterator->_prev;node* cur = pos.node_iterator;//連接pre->_next = new_node;new_node->_prev = pre;new_node->_next = cur;cur->_prev = new_node;}list<string> l1;
string s1 = "hello";
l1.push_back(s1);
l1.push_back(to_string(1234));

在這里插入圖片描述

6.5 完美轉發

模板中的&&萬能引用

void fun(int& x) { std::cout << "左值引用" << std::endl; };
void fun(const int& x) { std::cout << "const 左值引用" << std::endl; };
void fun(int&& x) { std::cout << "右值引用" << std::endl; };
void fun(const int&& x) { std::cout << "const 右值引用" << std::endl; };// 模板的&&不是右值引用,是萬能引用,既能接收左值,也能右值
// 引用類型的唯一作用是限制了接收的類型,后續使用都退化成了左值
// 想要保持左值和右值的屬性,要使用完美轉發
template <typename T>
void PerfectForward(T&& t)
{fun(t);
};PerfectForward(10);  //右值
int a;
PerfectForward(a);  //左值
PerfectForward(std::move(a));  //右值
const int b = 8;
PerfectForward(b);  //左值
PerfectForward(std::move(b));  //右值

上面的t后續都退化成了左值,想要保持傳入的屬性,就要加入std::forward保留屬性

fun(std::forward<T>(t));

使用場景
容器的插入等可以直接使用完美轉發,代替左值和右值兩個版本

7. 新的類功能

默認成員函數
原來c++類中,有6個默認成員函數:
1.構造函數
2.析構函數
3.拷貝構造函數
4.拷貝賦值重載
5.取地址重載
6.const取地址重載

最后重要的是前4個,后兩個用處不大。默認成員函數就是我們不寫編譯器會生成一個默認的
c++11新增了兩個:移動構造函數和移動賦值運算符重載

針對移動構造函數和移動賦值運算符重載有一些需要注意的點如下:

  • 如果沒有實現移動構造函數,且沒有實現析構函數、拷貝構造、拷貝賦值重載中的任意一個。那么編譯器會自動生成一個默認移動構造。默認生成的移動構造函數,對于內置類型成員匯之星逐成員按字節拷貝,自定義類型成員,則需要看這個成員是否實現移動構造,如果實現了就調用移動構造,沒有實現就調用拷貝構造
  • 如果沒有實現移動賦值重載,且沒有實現析構函數、拷貝構造、拷貝賦值重載中的任意一個。那么編譯器會自動生成一個默認移動賦值。默認生成的移動構造函數,對于內置類型成員匯之星逐成員按字節拷貝,自定義類型成員,則需要看這個成員是否實現移動賦值,如果實現了就調用移動,沒有實現就調用拷貝構造
  • 如果提供了移動構造或者移動賦值,編譯器就不會自動提供拷貝構造和拷貝賦值

類成員變量初始化
c++11允許在類定義時給成員變量初始缺省值,默認生成構造函數會使用這些缺省值初始化

強制生成默認函數的關鍵字default
c++11可以更好的控制要使用的默認函數,假設要使用某個默認的函數,但因為一些原因沒有默認生成,比如提供了拷貝構造,就不會生成移動構造,可以適用default關鍵字顯示指定移動構造生成

class Person{public:Person(const char* name = "", int age = 0):_name(name), _age(age){}Person(const Person& p):_name(p._name),_age(p._age){}Person(Person&& p) = default;private:bit::string _name;int _age;};int main(){Person s1;Person s2 = s1;Person s3 = std::move(s1);return 0;}

禁止生成默認函數的關鍵字delete
如果想要限制某些默認函數的生成,在c++98中,是該函數設置成private,并且只聲明補丁,止癢只要其他人想要調用就會報錯。在c++11中更簡單,只需在函數聲明上加上=delete即可,指示編譯器不生成對應函數的默認版本,修飾的為刪除函數

class Person{public:Person(const char* name = "", int age = 0):_name(name), _age(age){}Person(const Person& p) = delete;private:bit::string _name;int _age;};int main(){Person s1;Person s2 = s1;Person s3 = std::move(s1);}

繼承和多態中的final與override關鍵字
final修飾類或虛函數,表示不可被繼承或重寫。override檢測虛函數是否完成重寫

8. 可變參數模板

c++11的新特性可變參數模板能夠創建可以接收可變參數的函數模板和類模板,相比c++98/03,類模板和函數模板中只能含固定數量的模板參數,可變模板參數無疑是一個巨大的改進。然而由于可變模板參數比較抽象,使用起來需要一定的技巧,所以這塊還是比較晦澀的。掌握一些基礎的可變模板參數特性就可以了

// Args是一個模板參數包,args是一個函數形參參數包
// 聲明一個參數包Args...args,這個參數包中可以包含0到任意個模板參數。
template <class ...Args>void ShowList(Args... args){}

上面的參數args前面有省略號,所以它就是一個可變模板參數,把帶省略號的參數稱為“參數包”,里面包含了0到N(N>0)個模板參數。無法直接獲取參數包args中的每個參數,只能通過展開參數包的方式獲取每個參數,這時使用可變模板參數的一個主要特點,也是最大的難點,如何展開可變模板參數。由于語法不支持使用args[i]這樣方式獲取可變參數,所以我們用一些特殊方式一一獲取參數包

遞歸函數展開參數包

// 遞歸終止函數
void _ShowList()
{std::cout << std::endl;
}
//展開函數
template <class T, class ...Args>
void _ShowList(const T& value, Args ...args)
{std::cout << value << " ";_ShowList(args...);
}template <class ...Args>
void ShowList(Args ...args)
{_ShowList(args...);
}int main()
{ShowList(1, 2, 'x');ShowList(1, 2, 3.5);return 0;
}

逗號表達式展開
這種方式展開參數包,不需要通過遞歸終止函數,是直接在expand函數體中展開的,printarg不是一個遞歸終止函數,指示一個處理參數包每一個參數的函數。這種就地展開參數包的方式實現的關鍵是逗號表達式。逗號表達式會按順序執行,返回最后一個

expand函數中的逗號表達式也(printarg(args),0),也是按照這個執行順序,限制性printarg(args),在得到逗號表達式的結果0,同時還用到了c++11的另外一個特性–初始化列表,通過初始化列表來初始化一個變長數組,{(printarg(args), 0}將會展開成(printarg(arg1), 0),(printarg(arg2), 0), (printarg(arg3), 0), etc…),最終會創建一個元素值都為0的數組Int arr[sizeof…(args)]。由于是逗號表達式,在創建數組的過程中回顯執行逗號表達式前面的部分printarg(args)打印出參數,也就是說在構造int數組的過程中就將參數包展開了,這個參數的目的純粹是為了在數組構造的過程展開參數包

template <class T>void PrintArg(T t){cout << t << " ";}//展開函數
template <class ...Args>void ShowList(Args... args){int arr[] = { (PrintArg(args), 0)... };cout << endl;}}int main(){ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));

stl容器中empalce相關接口

 template <class... Args>void emplace_back (Args&&... args);

emplace系列接口,支持模板的可變參數,并且萬能引用。那么相對insert優勢在哪里

int main(){std::list< std::pair<int, char> > mylist;// emplace_back支持可變參數,拿到構建pair對象的參數后自己去創建對象
// 那么在這里我們可以看到除了用法上,和push_back沒什么太大的區別
mylist.emplace_back(10, 'a');mylist.emplace_back(20, 'b');mylist.emplace_back(make_pair(30, 'c'));mylist.push_back(make_pair(40, 'd'));mylist.push_back({ 50, 'e' });for (auto e : mylist)cout << e.first << ":" << e.second << endl;return 0;}

emplace是由模板參數包直接傳入參數,不會拷貝一個臨時對象。而pushback需要拷貝構造或移動構造。移動構造的消耗也不是很高

int main(){// 下面我們試一下帶有拷貝構造和移動構造的bit::string,再試試呢
// 我們會發現其實差別也不到,emplace_back是直接構造了,push_back// 是先構造,再移動構造,其實也還好。
std::list< std::pair<int, bit::string> > mylist;mylist.emplace_back(10, "sort");mylist.emplace_back(make_pair(20, "sort"));mylist.push_back(make_pair(30, "sort"));mylist.push_back({ 40, "sort"});return 0;}

在這里插入圖片描述

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

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

相關文章

JAVA學習筆記DAY12——MySQL基礎

文章目錄 數據庫概述為什么要使用數據庫相關概念關系型和非關系型RDBMS非RDBMS - NoSQL MySQL圖形化管理工具Navicat SQL前后端環境nginx 反向代理MD5加密 數據庫概述 為什么要使用數據庫 持久化&#xff1a;指把數據保存到可掉電存儲設備中&#xff0c;一般指將內存中的數據…

詳解歸一化、標準化、正則化以及batch normalization

文章目錄 what(是什么)where&#xff08;用在哪&#xff09;How&#xff08;如何用&&原理&#xff09;歸一化實現方式原理示例說明 標準化實現方式原理示例說明 正則化實現方式原理作用 Batch Normalizationpytorch中的batch normalization原理BN的作用 歸一化、標準化…

代理設計模式和裝飾器設計模式的區別

代理設計模式: 作用:為目標(原始對象)增加功能(額外功能,拓展功能) 三種經典應用場景: 1&#xff1a;給原始對象增加額外功能(spring添加事務,Mybatis通過代理實現緩存功能等等) 2&#xff1a;遠程代理&#xff08;網絡通信&#xff0c;輸出傳輸&#xff08;RPC&#xff0c;D…

【TB作品】智能臺燈,ATMEGA16單片機,Proteus仿真

智能臺燈 1 adc檢測光強光敏電阻 顯示電壓 2 光強太高 也就是高于臨界值 就關閉小燈 3 光強太低 也就是低于臨界值 就打開小燈 3 按鍵修改臨界值 顯示 實驗報告&#xff1a;基于ATMEGA16單片機的智能臺燈設計與Proteus仿真 1. 實驗背景 智能臺燈是一種能夠根據環境光強自動調…

代碼隨想錄第40天|動態規劃

完全背包 完全背包物品可以無限使用 01背包核心代碼 01背包中的二維dp數組的兩個for遍歷可顛倒, 而一維dp數組的一定先遍歷物品再遍歷背包容量狀態轉移方程(背包容量一定為遞減) 完全背包核心代碼 (只在完全背包中一維dp數組嵌套順序可顛倒, 實際題目需要確定遍歷順序) 狀…

【高考志愿】建筑學

目錄 一、專業介紹 1.1 專業定義 1.2 專業培養目標 1.3 核心課程 二、就業方向和前景 2.1 就業方向 2.2 專業前景 三、報考注意 四、行業趨勢與未來展望 五、建筑學專業排名 一、專業介紹 1.1 專業定義 建筑學&#xff0c;這一充滿藝術與科技魅力的學科&#xff0c;…

天線 有源 無源 參數

無源測試駐波比VSWR/回波損耗(Return Loss)≤2效率≥50%輸入阻抗50R10%增益天線方向圖3D場強圖方向性 有源測試 OTA 傳導測試&#xff1a;發射功率傳導測試&#xff1a;接收靈敏度總輻射功率TRP(Total Radiated Power)≥發射功率減3dB總接收靈敏度TIS&#xff08;Total Isotrop…

JDBC1(JDBC相關類與接口 ?連接mysql數據庫? 測試 不同數據庫廠商實現-MySQL和Oracle)

目錄 一、JDBC 1. JDBC相關類與接口 1.1 DriverManager 1.2 Connection 1.3 Statement 4.ResultSet 2. JDBC工作原理 二、連接mysql數據庫 1. 導入jar包 2. 使用DriverManager加載驅動類 3. Connection接口 4. Statement接口 5. ResultSet接口 ?編輯 6. 關閉并…

顯卡簡介

顯卡是計算機系統中一個重要的組成部分&#xff0c;它負責處理圖形和視頻輸出。顯卡的性能直接影響到計算機的圖形處理能力&#xff0c;因此在游戲、視頻編輯、3D渲染等需要高性能圖形處理的應用中&#xff0c;顯卡的選擇至關重要。本文將從顯卡的基本概念、性能指標、市場現狀…

【Node.JS】入門

文章目錄 Node.js的入門涉及對其基本概念、特點、安裝、以及基本使用方法的了解。以下是對Node.js入門的詳細介紹&#xff1a; 一、Node.js基本概念和特點 定義&#xff1a;Node.js是一個基于Chrome V8引擎的JavaScript運行環境&#xff0c;它使得JavaScript能夠運行在服務器…

【鴻蒙學習筆記】基礎組件Progress:進度條組件

官方文檔&#xff1a;Progress 目錄標題 作用最全屬性迭代追加進度賦值風格樣式 作用 進度條組件 最全屬性迭代追加 Progress({ value: 20, total: 100, type: ProgressType.Linear }).color(Color.Green)// 顏色.width(200)// 大小.height(50)// 高度.value(50)// 進度可更…

視頻轉音頻:怎樣提取視頻中的音頻?6個提取音頻的小技巧(建議收藏)

怎樣提取視頻中的音頻&#xff1f;當我們想從視頻中提取出聲音時&#xff0c;通常會遇到很多問題。無論是想單獨提取出視頻里的音頻&#xff0c;還是把它轉成方便儲存或者分享的音頻格式&#xff0c;這都會涉及到視頻轉音頻的一個需求。因此&#xff0c;在這篇指南里&#xff0…

Spring Cloud - 項目搭建

1、新建maven項目 新建maven項目&#xff0c;該項目為主項目 1、新建maven項目 2、設置項目類型 3、選擇項目原型 4、設置參數 5、等著完成 2、設置項目信息 1、右鍵&#xff0c;項目屬性 2、設置jdk版本 3、選擇jdk17 4、修改編譯版本 5、右鍵項目&#xff0c;選擇maven->u…

【吊打面試官系列-MyBatis面試題】模糊查詢 like 語句該怎么寫?

大家好&#xff0c;我是鋒哥。今天分享關于 【模糊查詢 like 語句該怎么寫?】面試題&#xff0c;希望對大家有幫助&#xff1b; 模糊查詢 like 語句該怎么寫? 第 1 種&#xff1a;在 Java 代碼中添加 sql 通配符。 string wildcardname “%smi%”; list<name> names …

CDH安裝和配置流程

這份文件是一份關于CDH&#xff08;Clouderas Distribution Including Apache Hadoop&#xff09;安裝的詳細手冊&#xff0c;主要內容包括以下幾個部分&#xff1a; 1. **前言**&#xff1a; - CDH是基于Apache Hadoop的發行版&#xff0c;由Cloudera公司開發。 - 相比…

技術派全局異常處理

前言 全局的異常處理是Java后端不可或缺的一部分&#xff0c;可以提高代碼的健壯性和可維護性。 在我們的開發中&#xff0c;總是難免會碰到一些未經處理的異常&#xff0c;假如沒有做全局異常處理&#xff0c;那么我們返回給用戶的信息應該是不友好的&#xff0c;很抽象的&am…

【一篇文章帶你搞懂--拉鏈表!!!拉鏈表的原理是什么!】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是書生?&#xff0c;今天主要和大家分享一下拉鏈表的原理以及使用,希望對大家有所幫助。 大家可以關注我下方的鏈接更多優質文章供學習參考。 &#x1f49e;&#x1f49e;代碼是你的畫筆&#xff0c;創新是你…

深入解析:WebKit的JavaScript引擎與V8引擎的比較研究

在現代Web開發中&#xff0c;JavaScript引擎是瀏覽器的核心組件之一&#xff0c;它們負責解析和執行JavaScript代碼。WebKit和V8是兩個非常著名的JavaScript引擎&#xff0c;分別被用于不同的瀏覽器和環境中。WebKit的JavaScript引擎最初是Nitro&#xff0c;后來被JavaScriptCo…

【超簡單-Java設計模式1】設計模式的定義、分類及七大設計原則

引言 Java設計模式從入門到精通-設計模式的定義、設計模式分類及七大設計原則 設計模式簡介 在軟件開發中&#xff0c;設計模式是解決常見設計問題的最佳實踐。它們為開發者提供了一種通用的解決方案&#xff0c;使得代碼更加靈活、可復用和可維護。在Java編程語言中&#x…

Flink 運行時架構

Flink 運行時的組件 作業管理器&#xff08;JobManager&#xff09;資源管理器&#xff08;ResourceManager&#xff09;任務管理器&#xff08;TaskManager&#xff09;分發器&#xff08;Dispatch&#xff09; JobManager 控制一個應用程序執行的主進程&#xff0c;也就是說…