C ++:エッセイ7 ---オペレーターの過負荷

a + b演算を実行すると、彼はabを返します。

例:複素数の加算を実現します。

//用C++类的方法实现复数加法
#include<string>
#include<iostream>

class Plus//定义一个复数类
{
public:
	//构造函数有两种情况,一种是对这个类有初始化;另一种是没有初始化(没有初始化的话把他们都赋值为0)
	Plus();
	Plus(double r,double i);
	virtual ~Plus();//析构函数
	Plus add(Plus &d);//这个方法是实现复数加法的方案,函数返回值是一个类
	void printf();
private:
	double real;//实步
	double imag;//虚步
};
Plus::Plus()
{
	real = 0;
	imag = 0;
}
 Plus::Plus(double r, double i)//如果有初始化的话把两个参数赋值进两个变量里边
{
	 real = r;
	 imag = i;
}
 Plus::~Plus()
 {
 
 }
 Plus Plus::add(Plus &d)//参数就是被加数
 {
	 Plus c;//实例化一个复数类c
	 c.real = real + d.real;//把参数提取进来跟我自身的一个加数(自身的话因为是已经被主函数传进来的对象进行初始化了),使他们两个的实部相加
	 c.imag = imag + d.imag;
	 return c;
 }
 void Plus::printf()
 {
	 std::cout << "(" << real << "," <<imag<< "i)" << std::endl;
 }
int main()
{
	Plus p0(6, 5);
	Plus p1(3, 4);//实例化一个对象并初始化
	Plus p2(5, -8);
	Plus p3,p4;
	p3 = p1.add(p2);
	p4 = p0.add(p3);
	std::cout << "p1=";
	p1.printf();
	std::cout << "p2=";
	p2.printf();
	std::cout << "p1+p2=";
	p3.printf();
	std::cout << "p0+p1+p2=";
	p4.printf();


	return 0;
}

結果:

これは、関連する機能を定義することによって実現されます。

オペレーターの過負荷:

    

上記のクラスを書き直して、演算子のオーバーロードを使用します。

#include<string>
#include<iostream>
//对运算符+进行重载
class Complex//定义一个复数类
{
public:
	//构造函数有两种情况,一种是对这个类有初始化;另一种是没有初始化(没有初始化的话把他们都赋值为0)
	Complex();
	Complex(double r,double i);
	virtual ~Complex();//析构函数
	Complex operator+(Complex &d);//这个方法是实现复数加法的方案,函数返回值是一个类
	void printf();
private:
	double real;//实步
	double imag;//虚步
};
Complex::Complex()
{
	real = 0;
	imag = 0;
}
Complex::Complex(double r, double i)//如果有初始化的话把两个参数赋值进两个变量里边
{
	 real = r;
	 imag = i;
}
Complex::~Complex()
 {
 
 }
Complex Complex::operator+(Complex &d)//比如说a+b,那么他的参数就是b(那么a跑哪里去了为什么只有一个参数)(事实上就是a来调用operator+来加上参数d的)
 {
	Complex c;//实例化一个复数类c
	 c.real = real + d.real;//把参数提取进来跟我自身的一个加数(自身的话因为是已经被主函数传进来的对象进行初始化了),使他们两个的实部相加
	 c.imag = imag + d.imag;
	 return c;
 }
 void Complex::printf()
 {
	 std::cout << "(" << real << "," <<imag<< "i)" << std::endl;
 }
int main()
{
	Complex p0(6, 5);
	Complex p1(3, 4);//实例化一个对象并初始化
	Complex p2(5, -8);
	Complex p3,p4;
	p3 =p1+p2;//为什么可以直接加呢?因为加号在类里面已经被重载了(不用像原来一样调用函数实现加法了)
	std::cout << "p1=";
	p1.printf();
	std::cout << "p2=";
	p2.printf();
	std::cout << "p1+p2=";
	p3.printf();
	return 0;
}

結果は同じです。

    
フレンド関数(つまり、この関数はこのクラスに属していませんが、このクラスのフレンドまたは親戚であるため、このクラスのプライベートメンバーにアクセスできます)(なぜオペレーター関数をフレンド関数にしたいのですか?アクセスしたいのでプライベートメンバーがこのクラスの機能でない場合、彼のプライベートメンバーにアクセスできません。どうすればよいですか?彼の友達からのみ)

次のように書き直します。ただし、この方法はお勧めしませんが、誰もが知っておく必要があります。

#include<string>
#include<iostream>
//对运算符+进行重载
class Complex//定义一个复数类
{
public:
	//构造函数有两种情况,一种是对这个类有初始化;另一种是没有初始化(没有初始化的话把他们都赋值为0)
	Complex();
	Complex(double r,double i);
	virtual ~Complex();//析构函数
	friend Complex operator+(Complex &c,Complex &d);//这个方法是实现复数加法的方案,函数返回值是一个类
	void printf();
private:
	double real;//实步
	double imag;//虚步
};
Complex::Complex()
{
	real = 0;
	imag = 0;
}
Complex::Complex(double r, double i)//如果有初始化的话把两个参数赋值进两个变量里边
{
	 real = r;
	 imag = i;
}
Complex::~Complex()
 {
 
 }
//注意这里作为友元函数不属于Complex,记得别写::
Complex operator+(Complex &c,Complex &d)
 {
	 return Complex(c.real+d.real,c.imag+d.imag);
 }
 void Complex::printf()
 {
	 std::cout << "(" << real << "," <<imag<< "i)" << std::endl;
 }
int main()
{
	Complex p0(6, 5);
	Complex p1(3, 4);//实例化一个对象并初始化
	Complex p2(5, -8);
	Complex p3,p4;
	p3 =p1+p2;
	std::cout << "p1=";
	p1.printf();
	std::cout << "p2=";
	p2.printf();
	std::cout << "p1+p2=";
	p3.printf();
	return 0;
}

最終結果は同じです。

25-32

--------動的メモリ管理

最初に概念を理解します。静的メモリ割り当てと動的メモリ割り当てとは何ですか?

静的メモリ割り当てと動的メモリ割り当て

静的メモリ割り当て:グローバルまたはローカル変数(オブジェクト)、コンパイル時のコンパイラは、変数またはオブジェクトのタイプに応じて必要なメモリスペースのサイズを知ることできます。システムが適切なときにそれらにメモリスペースを割り当てるように

動的メモリ割り当て:一部の操作オブジェクトは、プログラムの実行中にのみ決定できるため、コンパイラコンパイルにそれらのストレージスペースを予約できません。プログラムが実行されている場合にのみ、システムは実行時の要件に従ってメモリを割り当てます。これは動的メモリ割り当てと呼ばれます。 。動的割り当ては、空きストレージ領域で実行されます。(このようなメモリ管理は本当に動的です)

newを使用してint型のアドレス(メモリブロック、合計4バイト)を申請し、このポインタ変数に最初のアドレスを指定します。変数名はiです。

 

たとえば、0から18までのアドレスがあり、iという変数がスタックスペースで宣言されています。iはポインタ変数なので、アドレスを格納します。このアドレスはどこから来たのですか?newによって新しいintメモリブロックが生成され、彼を格納するために彼の初期アドレスが返されます。初期アドレスは4で、intは4バイトを占有します(4567これらの4バイトはnewからのメモリブロックであり、彼の初期アドレス4を配置します。このポインタ変数に格納されます)

delete i;の操作は、4567の4つのメモリブロックをオペレーティングシステムに返すことですが、ポインタ変数iは実際にはスタックで生成されたローカルであるため、ポインタ変数は変更されていません。変数、それは解放されず、そのアドレスはまだそこにありますが、このアドレスの内容は解放されているので、安全のために、iをNULLに設定する必要があります。このようにして、次の図になり、iのすべてがこれ以上、廃止されたポインタになりました。このポインタは役に立ちません。NULLに割り当てられたポインタを逆参照しようとすると、エラーが発生します。

 

 

#include<stdio.h>
#include<iostream>
#include<string>
class Company
{
 public:
	 Company(std::string theName);
	 virtual void printInfo();
 protected:
	std::string name;
};
class TechCompany :public Company
{
public:
	TechCompany(std::string theName, std::string product);
	virtual void printInfo();
private:
	std::string product;
};
Company::Company(std::string theName)
{
	name = theName;
}
void Company::printInfo()
{
	std::cout << "这个公司的名字叫:" << name << std::endl;
}
TechCompany::TechCompany(std::string theName, std::string product):Company(theName)
{
	this->product = product;

}
void TechCompany::printInfo()
{
	std::cout << name << "公司主打产品是:" << product << std::endl;
}
int main()
{
	Company *company = new Company("apple");
	company->printInfo();
	delete company;
	company = NULL;
	company = new TechCompany("apple", "苹果");
	company->printInfo();
	delete company;
	company = NULL;
	return 0;
}

動的配列:

 

 

動的配列を削除します。

#include<iostream>
#include<string>
int main()
{
	unsigned int count = 0;//count是用来动态的定义的
	std::cout << "请输入数据元素的个数:" << std::endl;
	std::cin >> count;//输入存放到count里面
	int *x = new int[count];//定义一个指针,用new来对它进行初始化,给他申请内存,这块的申请内存是在程序运行的时候申请的,而不是编译的时候申请的,所以我们说他是动态内存,
	//是从堆里边申请的,而不是栈里边,一般我们像变量,局部变量是从栈里边申请的数据,而这些动态申请呢我们程序由程序在运行的时候申请的,这些是从堆里边申请的,只是两块不同的内存。
	for (int i = 0; i < count; i++)//初始化
	{
		x[i] = i;
	}
	for (int i = 0; i < count; i++)//打印
	{
		std::cout << "x[" << i << "]=" << x[i] << std::endl;
	}
	return 0;
}

  新しいステートメントを使用して割り当てられるため、彼のメモリはヒープに割り当てられ、関数の終了時に解放されません。ローカル変数の場合は、スタック内のプログラムによって自動的に割り当てられ(コンパイラによって自動的に割り当てられます)、関数呼び出しの最後に自動的に解放されます。

//从函数和方法返回内存
#include<iostream>
int *newInt(int value);//1声明一个函数,这个函数前边加一个*号,说明他的返回值类型是int*,是一个指向整型变量的一个地址,一个指针
int main()
{
	int *x = newInt(20);//2、6定义一个指针变量x,这是一个指向整数的指针变量,他赋值为newInt(20)这个函数的返回值,因为这个函数的返回值是一个地址,
	//因为声明函数的时候加了一个*号是一个指针的标志,说明他的返回值是一个地址。调用他
	std::cout << *x<<std::endl;//7打印地址
	delete x;//8把他释放掉
	x = NULL;//9把他的指针填充NULL,使得指针不会被随意的乱用
	return 0;//然后结束整个程序
}
int *newInt(int value)
{
	int *myInt = new int;//3这个里边它new一个整型的变量,在堆里边申请一个整型的内存块
	*myInt = value;//4然后给他赋值,赋值为这个参数value的值(*myInt使用*给他解引用)
	return myInt;//5赋值之后返回他的地址(6处接到地址)
}

 //関数にローカル変数へのポインタを返させないのはなぜですか

住所による電話:

#include<iostream>
void swap(int *x, int *y);
int main()
{
	int a, b;
	a = 3;
	b = 5;
	swap(&a, &b);//传引用过去,传他们的地址过去
	std::cout << "a=" << a << std::endl;
	std::cout << "b=" << b << std::endl;
	return 0;
}
void swap(int *x, int *y)//这里要接的两个形参定义为指针类型,我们就可以接到他的地址
{
#if 0
	int temp;
	temp = *x;
	*x = *y;
	*y = temp;
#endif
	*x ^= *y;
	*y ^= *x;
	*x ^= *y;
}

ローカル変数はスタック上にあり、関数の最後に自動的に解放されるため、関数は自身のローカル変数のポインターを戻り値として受け取るべきではありません。(スタックはこの関数の最後に解放されるため、彼のアドレスを返します。メイン関数のメインコードで参照したアドレスは予測できない値になります。解放されるため、内部にはガベージ値しかありません。または他の変数が間違っている可能性があります)

関数が隠れた危険を残さずにポインタを返すようにしたい場合、それは動的に割り当てられたメモリブロックのベースアドレスのみにすることができます。(動的割り当てのため、deleteステートメントのみが彼をヒープ内で解放できます。)

PS:2つの概念を強調します

関数ポインター:(2つの単語のポインターを強調)は、この関数ポインターが実際にはポインターであり、ストレージアドレス変数であることを示しています。(関数の最初のアドレスを指すポインター変数)

#include<stdio.h>
int fun(int x, int y);
int main()
{
	int i, a, b;
	int(*p)(int a,int b);//声明函数指针,前边多了括号(*p)(说明他是一个指针变量,指向函数的指针变量)后边的(),表明它是一个函数
	scanf("%d", &a);
	p = fun;//给函数指针p赋值,使他指向函数f
	printf("请输入个数字:\n");
	for (i = 0; i < 10; i++)
	{
		scanf("%d", &b);
		a = (*p)(a, b);//通过指针p调用函数f。(p来代替fun)
	}
	printf("The max number is:%d", a);
	return 0;
}
int fun(int x, int y)
{
	int z; 
	z = (x > y) ? x : y;
	return(z);
}

ポインタ機能:

関数は、整数データ値、文字タイプ値、および実数タイプ値を戻すことができます。また、アドレス単位を指すようにポインタータイプデータを戻すこともできます。

#include<iostream>
int *newInt(int value);//1声明一个函数(前边*newInt没有用括号括起来,说明是一个函数,括起来的话就是一个指针了),这个函数前边加一个*号,说明他的返回值类型是int*,是一个指向整型变量的一个地址,一个指针
int main()
{
	int *x = newInt(20);//2、6定义一个指针变量x,这是一个指向整数的指针变量,他赋值为newInt(20)这个函数的返回值,因为这个函数的返回值是一个地址,
	//因为声明函数的时候加了一个*号是一个指针的标志,说明他的返回值是一个地址。调用他
	std::cout << *x<<std::endl;//7打印地址
	delete x;//8把他释放掉
	x = NULL;//9把他的指针填充NULL,使得指针不会被随意的乱用
	return 0;//然后结束整个程序
}
int *newInt(int value)
{
	int *myInt = new int;//3这个里边它new一个整型的变量,在堆里边申请一个整型的内存块
	*myInt = value;//4然后给他赋值,赋值为这个参数value的值(*myInt使用*给他解引用)
	return myInt;//5赋值之后返回他的地址(6处接到地址)
}

-----コピーコンストラクタ

 

36-38

おすすめ

転載: blog.csdn.net/m0_37957160/article/details/109014853