C++ レビュー ノート - 入門書 第 5 版

記事ディレクトリ

1. 参考文献とポインタ

1. 引用

通常、変数を初期化すると、初期値が新しく作成されたオブジェクトにコピーされます。ただし、参照を定義する場合、プログラムは、初期値を参照にコピーするのではなく、参照をその初期値にバインドします。初期化されると、参照はその初期値オブジェクトにバインドされたままになります。参照を別のオブジェクトに再バインドできないため、参照を初期化する必要があります。
参照はオブジェクトではなく、既存のオブジェクトの別の名前にすぎません。
参照を定義した後、その参照に対して実行されるすべての操作は、その参照にバインドされているオブジェクトに対して実行されます。

refval = 2;		// 把2赋给 refVal 指向的对象,此处即是赋给了ival
int ii = refVal;//与ii=ival执行结果一样

2.ポインタ

ポインタは、別の型を「指す」複合型です。参照と同様に、ポインタも他のオブジェクトへの間接的なアクセスを提供します。ただし、ポインターと参照の間には多くの違いがあります。まず、ポインター自体がオブジェクトであるため、ポインターの割り当てとコピーが可能であり、ポインターのライフ サイクル中にいくつかの異なるオブジェクトを指すことができます。第 2 に、ポインタを定義するときに初期値を割り当てる必要がありません。他の組み込み型と同様、ブロック スコープ内で定義されたポインターは、初期化されていない場合、値が未定義になります。

2.1 ポインタを使用したオブジェクトへのアクセス

ポインタがオブジェクトを指している場合、逆参照演算子(演算子 *) はオブジェクトにアクセスできます

int ival = 42;
int *p = &ival;	//p存放着变量ival的地址,或者说p是指向变量ival的指针
cout << *p;		// 由符号*得到指针p所指的对象,输出 42

ポインタを逆参照すると、それが参照するオブジェクトが生成されるため、逆参照された結果に値を代入すると、実際にはポインタが指すオブジェクトに値を代入することになります。

*p = 0;			// 由符号*得到指针p所指的对象,即可经由P为变量ival赋值
cout << *p;		//输出0如上述程序所示,为*p赋值实际上是为p所指的对象赋值。
<!--解引用操作仅适用于那些确实指向了某个对象的有效指针。-->

2.2 ポインタの値またはポインタが指すオブジェクトの値の変化

代入ステートメントがポインタの値を変更するのか、それともポインタが指すオブジェクトの値を変更するのかを理解するのが難しい場合があります。最良の方法は、代入は常に等号の左側にあるオブジェクトを変更することを覚えておくことです。サイン。次のステートメントを書くとき:

pi = &ival;  // pi 的值被改变,现在pi 指向了ival

これは、pi に新しい値を割り当てることを意味し、pi に格納されているアドレス値を変更することを意味します。逆に、次のような文を書くとします。

*pi = 0;		// ival的值被改变,指针pi并没有改变

すると、 *pi (つまり、ポインタ pi が指すオブジェクト) が変化します。

3. 割り当てとポインタ

ポインタと参照は両方とも、他のオブジェクトへの間接的なアクセスを提供できます。ただし、特定の実装の詳細では大きく異なります。最も重要な点は、参照自体はオブジェクトではないということです。参照が定義されると、その参照を別のオブジェクトにバインドすることはできませんこの参照をその後使用するたびに、最初にバインドされていたオブジェクトにアクセスします
ポインタとそれが格納するアドレスとの間にはそのような制限はありません。他の変数と同様に (参照でない限り)、
ポインターに値を割り当てることは、新しいアドレスを格納し、新しいオブジェクトを指すことを意味します。

int i =42;
int *pi =0;		//pi被初始化,但没有指向任何对象
int *pi2 = &i;	//pi2被初始化,存有i的地址
int *pi3;		//如果pi3定义于块内,则pi3的值是无法确定的

pi3= pi2;		//pi3和pi2指向同一个对象i
pi2 = 0;		//现在pi2不指向任何对象了

4. ポインタの参照

参照自体はオブジェクトではないため、参照へのポインタを定義することはできません。ただし、ポインタはオブジェクトであるため、
ポインタへの参照が存在します。

int i=42;
int *pi ;		// p是一个int型指针
int *&r =pi;		//r是一个对指针p的引用

r = &i;			//r引用了一个指针,因此给上赋值&i就是令p指向i
*r =0;			//解引用r得到i,也就是p指向的对象,将i的值改为0

r の型を理解する最も簡単な方法は、r の定義を右から左に読むことです。変数名に最も近い記号 (この場合、&r の記号 &) は変数の型に最も直接的な影響を与えるため、r は参照になります。宣言子の残りの部分は、r がどの型を参照するかを決定するために使用されます。この例の記号 * は、r がポインターを参照することを示します。最後に、宣言の基本データ型部分は、r が int ポインターを参照することを示しています。

2.文字列

1. Stringオブジェクトの初期化方法

string s1			//默认初始化,s1是一个字符串
string s2(s1)		//s2是s1的副本
string s2 == s1		//等价于上面
string s3("value")	//s3是字面值value的副本,除了最后一个空字符外
string s3 = "value"	//等价于上面
string s4(n,'c')	//n个连续的c组成的串

2. 文字列オブジェクトの操作

os<<s	//将s写到输出流os当中,返回os
is>>s	//从is中读取字符串赋给s,字符串以空白分隔,返回is
getline(is, s)//从is中读取一行赋给s,返回is
s.empty()	//s为空返回true,否则返回false
s.size()	//返回s中字符的个数
s[n]		//返回s中第n个字符的引用,位置n从0计起
s1+s2	//返回s1和s2连接后的结果
sl=s2	//用s2的副本代替s1中原来的字符
s1==s2	//如果s1和s2中所含的字符完全一样,则它们相等;string对象的相
s1!=s2	//等性判断对字母的大小写敏感
<<=>>=	//利用字符在字典中的顺序进行比较,且对字母的大小写敏感

第 1 章では、int や double などの組み込み型の値を読み書きするための標準ライブラリの iostream の使用方法を紹介しました。同様に、IO 演算子を使用して文字列オブジェクトの読み取りと書き込みを行うこともできます。

//注意:要想编译下面的代码还需要适当的#include语句和using声明
int main()
{
    
    
	string s;
    cin >> s;			//如果程序的输入是“     Hello World!     "
    cout << s << endl;	//则输出将是“Hello”,输出结果中没有任何空格。
    return 0;    
}

string s1, s2;		// 把第一个输入读到 s1 中,第二个输入读到 s2 中
cin >> s1 >> s2;	//输出两个 string对象
cout << s1 << s2 << endl;//输出HelloWorld! 

3. getline を使用して行全体を読み取る

場合によっては、最終文字列への入力中に空白文字を保持したい場合がありますが、この場合は、元の >> 演算子の代わりに getline 関数を使用する必要があります。getline 関数のパラメータは入力ストリームと文字列オブジェクトです。この関数は、改行文字に遭遇するまで指定された入力ストリームからコンテンツを読み取り (改行文字も読み込まれることに注意してください)、その後、読み取ったコンテンツを Go に保存します。その文字列オブジェクトにコピーします (改行文字は保存されないことに注意してください)。getline は、入力が改行文字で始まっている場合でも、改行文字に遭遇するとすぐに読み取り操作を終了し、結果を返します。入力が実際に改行文字で始まる場合、結果は空の文字列になります。
input 演算子と同様に、getline もストリーム引数を返します。つまり、入力演算子を判定条件(Ctrl+D/Z)として利用できるので、getlineの結果も条件として利用することができます。たとえば、1 行に 1 単語ではなく、一度に 1 行全体を出力するように、以前のプログラムを書き直すことができます。

int main()
{
    
    
	string line;	//每次读入一整行,直至到达文件末尾
	while (getline(cin, line))
		cout << line << endl;
	return 0;
}

line には改行文字が含まれていないため、手動で改行演算子を追加します。いつものように、end1 を使用して現在の行を終了し、表示バッファをフラッシュします。

4. リテラル値と文字列を追加する

string s4 = s1 + ",";		//正确;把一个string对象和一个字面值相加
string s5 = "hello" + ",";	//错误;两个运算的对象都不是string
string s6 = s1 + "hello" + "," ;//正确;每个加法运算符都有一个string对象
string s7 = "hello" + "," + s1;	//错误;不能将两个字面值相加

5. for ループを使用して文字列内の文字を変更します。

string s("Hello World!!!");//转换成大写形式。
for (auto &c :s)		// 对于s中的每个字符(注意:C是引用)
	c = toupper(c);		//c是一个引用,因此赋值语句将改变s中字符的值
	cout << s << endl;	

添字を使用した反復の実行
別の例は、s の最初の単語を大文字にすることです。


//依次处理s中的字符直至我们处理完全部字符或者遇到一个空白
for (decltype(s.size())index =0; index != s.size() && !isspace(s[index]); ++index)
	s[index] = toupper(s[index]);		//将当前字符改成大写形式
//index的类型是由 decltype关键字决定的,保证下标小于size()的值就可以了。

3. ベクトル

1. ベクトルオブジェクトを定義して初期化する

vector<T> vl		//v1是一个空vector,它潜在的元素是T类型的,执行默认初始化
vector<T> v2(v1)	//v2中包含有v1所有元素的副本
vector<T> v2 = vl	//等价于v2(v1),v2中包含有v1所有元素的副本
vector<T> v3(n, val)//v3包含了n个重复的元素,每个元素的值都是val 
vector<T> v4(n)		//v4包含了n个重复地执行了值初始化的对象
vector<T> v5{
    
    a,b,c.}	//v5包含了初始值个数的元素,每个元素被赋予相应的初始值
vector<T> v5 = {
    
    a,b, c.}	//等价于v5{a,b,c...}

4. イテレータ

標準コンテナ反復子の演算子

*iter	返回迭代器iter所指元素的引用
iter->mem	解引用iter并获取该元素的名为mem的成员,等价于(*iter).mem
++iter	令iter指示容器中的下一个元素
--iter  令iter指示容器中的上一个元素
iterl == iter2		判断两个迭代器是否相等(不相等),如果两个迭代器指示的是同一个元
iterl != iter2		素或者它们是同一个容器的尾后迭代器,则相等;反之,不相等

ポインタと同様に、それが示す要素はイテレータを逆参照することによっても取得できます。逆参照を実行するイテレータは正当なものであり、実際に要素を示している必要があります。不正な反復子または後続の反復子を逆参照しようとすると、未定義の動作が行われます。

テキストテキストデータを読み取る:

// 依次输出 text 的每一行直至遇到第一个空白行为止
for (auto it = text.cbegin();
	it != text.cend() && !it->empty()++ it)
	cout << *it << endl;

イテレータ操作

二分探索法

auto mid = vi.begin() + vi.size()/2

5. アレイ

初期化

このような配列は文字列リテラルで初期化できます。このメソッドを使用するときは、文字列リテラルの末尾に null 文字があることに注意してください。この null 文字も、文字列内の他の文字と同様に文字配列にコピーされます。

char al[l] = {
    
    'c','+'}		// 列表初始化,没有空字符
char a2[] = {
    
    'c','+','\0'}	//列表初始化,含有显式的空字符
char a3[] = "C++"			//自动添加表示字符串结束的空字符
const char a4[6] = "Daniel";	//错误:没有空间可存放空字符!

文字列リテラル "Daniel" は 6 文字の長さしかないように見えますが、配列のサイズは少なくとも 7 でなければならず、6 つの位置にリテラルの内容が保持され、1 つの位置に終端の null 文字が保持されます。

配列の内容を初期値として他の配列にコピーしたり、配列を使用して他の配列に値を割り当てることはできません。

int a[] = {
    
    1,2,3};	
int a2[] = a;	//err
a2 = a;			//err

複雑な配列宣言を理解する

int *ptrs[10];
int (*Parray)[10] = &arr;
int (&arrRef)[10] = arr;

デフォルトでは、型修飾子は右から左にバインドされます。ptrs の場合、その意味を右から左に理解するのは比較的簡単です (52 ページのセクション 2.3.3 を参照)。まず、サイズ 10 の配列を定義し、その名前が ptrs であることを知り、次に配列ストアがint へのポインタ。

しかし、パレーにとって、右から左へ理解することは合理的ではありません。配列の次元は宣言された名前に従うため、配列の場合は右から左に読むよりも内側から外側に読み取る方がはるかに優れています。内側から外側への順序は、Parray の意味をより深く理解するのに役立ちます。最初は括弧で囲まれた部分です。*Parray は Parray がポインターであることを意味し、次に右側を見ると、Parray がへのポインターであることがわかります。サイズ 10 の配列の場合、最後に左側を観察すると、配列内の要素が int であることがわかります。最終的な意味は明らかで、Parray は 10 個の要素を含む int 配列を指すポインターです。同様に、(&arrRef) は arrRef が参照であることを意味し、参照するオブジェクトはサイズ 10 の配列であり、配列内の要素の型は int です

もちろん、修飾子の数に特別な制限はありません。

int*(&arry)[10]-ptrs;// arry是数组的引用,该数组含有10个指针

上のステートメントを内側から外側に順番に読んでください。まず、arry が参照であることがわかります。次に、右側を見ると、arry によって参照されるオブジェクトがサイズ 10 の配列であることがわかります。最後に、if左側を見ると、配列の要素の型が int へのポインタであることがわかります。このように、arry は 10 個の int ポインターを含む配列への参照になります。
配列宣言の意味を理解する最良の方法は、配列名から始めて、配列宣言を内側から外側に読んでいくことです。

配列とポインタ

配列の要素もオブジェクトです。配列の添字演算子を使用して、配列の指定された位置にある要素を取得します。したがって、他のオブジェクトと同様に、配列要素に対してアドレス演算子を使用すると、要素へのポインタが取得されます。

string nums[] =("one","two""three"}//数组的元素是string对象
string *p= &nums[0];				//p指向nums的第一个元素

//然而,数组还有一个特性:在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针:
string *p2 = nums;//等价于p2 = &nums[0]
++p2;			//p2指向nums[2]

上記のことから、場合によっては配列操作が実際にはポインター操作であることがわかりますが、この結論には多くの隠された意味が含まれています。1 つの意味は、配列を auto 変数の初期値として使用する場合、推論される型は配列ではなくポインターになるということです ( decltype によって回避可能)。

int ia[]=0,1,2,3,4,5,6,7,8,9}// ia是一个含有10个整数的数组
auto ia2(ia);					// ia2 是一个整型指针,指向ia的第一个元素
ia2 = 42;						// 错误:ia2是一个指针,不能用int 值给指针赋值

ポインタはイテレータでもあります

6. 機能

1. 参照渡しと値渡し

他の変数と同様に、仮パラメータの型によって、仮パラメータと実パラメータがどのように相互作用するかが決まります。仮パラメータが参照型の場合、対応する仮パラメータにバインドされます。そうでない場合は、実パラメータの値がコピーされて、仮パラメータに割り当てられます。仮パラメータと実パラメータは、2 つの独立したオブジェクトです。

2.値パラメータを渡す

ポインタパラメータ

ポインターは他の非参照型と同様に動作します。ポインタのコピー操作が実行されると、ポインタの値がコピーされます。コピー後、2 つのポインタは異なるポインタになります。ポインタを使用すると、ポインタが指すオブジェクトに間接的にアクセスできるため、ポインタが指すオブジェクトの値はポインタを介して変更できます。

int n = 0,i=42;
int *p= &n, *q= &i;	//p指向n;q指向主
*p=42;				//n的值改变;P不变
P=q;				//p现在指向了主;但是主和n的值都不变

ポインター パラメーターも同様に動作します。

//该函数接受一个指针,然后将指针所指的值置为0
void reset(int *ip)
{
    
    
    *ip=0;		//改变指针ip所指对象的值
    ip=0;		//只改变了ip的局部拷贝,实参未被改变
}

リセット関数を呼び出した後、実パラメータが指すエッジは 0 に設定されますが、実パラメータ自体は変更されません。

int i=42;
reset(&i);		//改变主的值而非土的地址
cout << "i" << i << endl;	//输出i=0
ポインタパラメータを使用して2つの整数の値を交換する方法
#include <iostream>
using namespace std;
int swap(int *a,int *b);
int main()
{
    
    
	int *p,*q;
	int min=10;
	int max=20;
	 p=&min;    
	 q=&max;    
	cout<<"交换前:a= "<<min<<",b= "<<max<<endl;
	swap(p,q);
	cout<<"交换后:a= "<<min<<",b= "<<max<<endl;
	return 0;
}
int swap(int *a,int *b)
{
    
    
	int c;
	 c=*a;
	*a=*b;
	*b=c;
}

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムが存在する可能性があります。画像を保存して直接アップロードすることをお勧めします (img-R6OUs0vx-1691733924503) (C:\Users\lijiale\AppData\Roaming\Typora\) typora-user-images\ image-20230718110415925.png)]

p と q はそれぞれ 2 つの数値のアドレスであり、アドレスの内容を取得することで数値の値が得られますが、交換する場合はポインタが指す数値も交換する必要があります。ただし、下記の場合は交換できません。

#include <iostream>
using namespace std;
int swap(int *a,int *b);
int main()
{
    
    
	int *p,*q;
	int min=10;
	int max=20;
	 p=&min;
	 q=&max;	
	cout<<"交换前:a= "<<min<<",b= "<<max<<endl;
	swap(p,q);
	cout<<"交换后:a= "<<min<<",b= "<<max<<endl;
	return 0;
}
int swap(int *a,int *b)
{
    
    
	int *c;
	 c=a;
	 a=b;
	 b=c;	 
}

これは、スワップ関数の本体内では、2 つの仮パラメータ ポインタ自体の値のみが交換され、実際のパラメータには影響しないためです。このとき、仮引数にprint文があれば、確かに呼び出された関数内でポインタ値が交換されていることがよくわかりますが、これはローカルスコープでのみ有効であり、戻り値の場合は無効になります。呼び出しが完了した後、main 関数に戻ります。

3. 参照パラメータを渡す

参照パラメータを使用すると、関数で 1 つ以上の実パラメータの値を変更できます。

コピーを避けるために参照を使用します。関数が参照パラメーターの値を変更する必要がない場合は、定数参照を使用するのが最善です。

bool isShorter(const string &s1,const string &s2)
{
	return s1.size() < s2.size();
}

仮パラメータを使用して暗黙的に追加情報を返す

1 つの方法は、位置と数量という 2 つのメンバーを含む新しいデータ型を定義することです。別の簡単な方法もあります。追加の参照引数を関数に渡して、文字の出現回数を保存できます。

//返回s中c第一次出现的位置索引
//引用形参occurs负责统计c出现的总次数
string::size _type find char(const string &s, char c,
							string::size _type &occurs)
{
    auto ret = s.size();	// 第一次出现的位置(如果有的话)
	occurs = 0;				//设置表示出现次数的形参的值
	for (decltype(ret) i = 0;!= S.size();++i) {
        if (s[il == c){
            if (ret ==  S.size())
				ret = i;	//记录c第一次出现的位置
            ++occurs;		//将出现的次数加1
        }
     }
return ret;			//出现次数通过occurs 隐式地返回
}

find_char 関数を呼び出すときは、検索範囲としての文字列オブジェクト、検索する文字、文字の出現数を保存するために使用される size_type の 3 つの実際のパラメータを渡す必要があります。

4.配列パラメータ

int a[] = {0,1,2};	//含有3个整数的数组
int a2[]=a	;		//错误:不允许使用一个数组初始化另一个数组
a2 = a;				//错误:不能把一个数组直接赋值给另一个数组

したがって、配列パラメータを値で使用することはできません。

ただし、配列はポインターに変換されるため、配列を関数に渡すとき、実際には配列の最初の要素へのポインターを渡します。

配列を値で渡すことはできませんが、仮パラメータを配列のような形式で記述することができます。

//尽管形式不同,但这三个print 函数是等价的
//每个函数都有一个const int*类型的形参
void print(const int*);	
void print(const int []);		//可以看出来,函数的意图是作用于一个数组
void print(const int[10]);		// 这里的维度表示我们期望数组含有多少元素,实际不一定
//尽管表现形式不同,但上面的三个函数是等价的:每个函数的唯一形参都是const int*类型的。当编译器处理对 print 函数的调用时,只检查传入的参数是否是const int*类型:
int i=0,j[2] ={0,1);
print(&i);					// 正确:&i的类型是int*
print(j);					// 正确:j转换成 int*并指向j[0]

print 関数に配列を渡すと、実際のパラメータは配列の最初の要素へのポインタに自動的に変換され、配列のサイズは関数呼び出しには影響しません。

5. 配列ポインタを返す

配列はコピーできないため、関数は配列を返すことができません。ただし、関数は配列へのポインタまたは参照を返すことができます (「5. 複雑さ」を参照)。構文的に言えば、配列へのポインターまたは参照を返す関数を定義するのは面倒ですが、このタスクを簡素化する方法がいくつかあります。最も簡単なのは、型エイリアスを使用することです。

typedef int arrT[10];// arrT是一个类型别名,它表示的类型是含有10个整数的数组
using arrT = int[10];// arrT的等价声明
arrT* func(int i);	//func返回一个指向含有10个整数的数组的指针

ここで、arrT は 10 個の整数の配列のエイリアスです。配列を返すことができないため、戻り値の型を配列へのポインタとして定義します。したがって、 func 関数は int 引数を受け入れ、10 個の整数を含む配列へのポインタを返します。

配列ポインタを返す関数を宣言する

型エイリアスを使用せずに func を宣言するには、名前を定義した後の配列の次元に留意する必要があります。

int arr[10];// arr是一个含有10个整数的数组
int *pl[10];//p1是一个含有10个指针的数组
int (*p2)[10] = &arr;//p2是一个指针,它指向含有10个整数的数组

これらの宣言と同様、配列ポインターを返す関数を定義する場合は、配列の次元が関数名の後に続く必要があります。ただし、関数のパラメーター リストは関数名の後に続き、パラメーター リストは配列の次元の前に置く必要があります。したがって、配列ポインターを返す関数の形式は次のようになります。

Type (*function (parameter _list) ) [dimension]
类似于其他数组的声明,Type 表示元素的类型,dimension 表示数组的大小。(*function(parameter _list))两端的括号必须存在,就像我们定义p2时两端必须有括号一样。如果没有这对括号,函数的返回类型将是指针的数组。
举个具体点的例子,下面这个func函数的声明没有使用类型别名:
int (*func(int i))[10];
可以按照以下的顺序来逐层理解该声明的含义:
func(int i)表示调用func函数时需要一个int类型的实参。
(*func(int i))意味着我们可以对函数调用的结果执行解引用操作。
(*func (int i))[10]表示解引用func的调用将得到一个大小是10的数组。
int (*func (int i))[10] 表示数组中的元素时int类型

改善: 末尾の戻り値の型

auto func(int i) -> int(*)[10];

6. 関数のオーバーロード

2 つの関数は、戻り値の型以外のすべてを同じにすることはできません。

7. カテゴリ

const メンバー関数が参照の形式で *this を返す場合、その戻り値の型は定数参照になります。

宣言では、Type は要素の型を表し、dimension は配列のサイズを表します。(*function(parameter _list)) p2 を定義するときに両端に括弧が必要であるのと同様に、両端に括弧が存在する必要があります。これらの括弧がないと、関数の戻り値の型はポインターの配列になります。
具体的な例を挙げると、次の func 関数の宣言では型エイリアスが使用されていません:
int (*func(int i))[10];この宣言の意味は、次の順序で階層
ごとに理解できます。
(int i) func 関数を呼び出すときに int 型の実パラメータが必要であることを示します。
(*func(int i)) は、関数呼び出しの結果に対して逆参照操作を実行できることを意味します。
(*func (int i))[10] は、逆参照 func の呼び出しでサイズ 10 の配列を取得することを意味します。
int (*func (int i))[10] は配列内の要素の int 型を表します


改进:尾置返回类型

```c++
auto func(int i) -> int(*)[10];

6. 関数のオーバーロード

2 つの関数は、戻り値の型以外のすべてを同じにすることはできません。

const メンバー関数が参照の形式で *this を返す場合、その戻り値の型は定数参照になります。

関数の非 const バージョンは定数オブジェクトでは使用できないため、const メンバー関数は定数オブジェクトに対してのみ呼び出すことができます。

他の

右辺値参照 右辺値参照

不必要なコピー = 盗む

右辺値:

//int实验
a + b = 42;//err
//string实验
string s1("Hello");
string s2("World");
s1 + s2 = s2;//pass,s1 = Hello,s2 = World
string() = "World";//pass 临时对象也是右值
//complex实验
complex<int> c1(3,8),c2(1,0);
c1 + c2 = complex<int>(4,9); //pass,c1:(3,8),c2:(1,0)
complex<int>() = complex<int>(4,9);//pass

右辺値に対しては操作を実行できません。
ここに画像の説明を挿入します

foo()返回的是值(int),在对右值进行取地址操作&foo(),是不允许的

使用法:

对于insert操作,提供了两个函数:
1.copy
insert(...,&x)	//x是普通的值
2.move
insert(...,&&x) //x是右值(临时对象),此时取右值引用

ベクトルには Mystring が含まれているため、クラス Mystring には 2 つのコンストラクターがあります。move は浅いコピーです。
ここに画像の説明を挿入します

ディープコピーとシャローコピー:

ここに画像の説明を挿入します

メモリ管理

ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します

可変個引数テンプレート

例 1. 変数テンプレート パラメーター (再帰呼び出し)

ここに画像の説明を挿入します

最大関数比率サイズ

ここに画像の説明を挿入します

ハンドル印刷機能

例 2. 再帰的な継承

処理するのは型(type)、クラステンプレートを使用

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムが存在する可能性があります。画像を保存して直接アップロードすることをお勧めします (img-TEmUDRpJ-1691734666845) (C:\Users\lijiale\AppData\Roaming\Typora\) typora-user-images\ image-20230713113744487.png)]

例 3. 再帰的複合

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムが存在する可能性があります。画像を保存して直接アップロードすることをお勧めします (img-N4VzmZjn-1691734666846) (C:\Users\lijiale\AppData\Roaming\Typora\) typora-user-images\ image-20230713115717968.png)]

おすすめ

転載: blog.csdn.net/Strive_LiJiaLe/article/details/132229951