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