文章目录
4.5.3 自增(递增)运算符重载
作用:通过重载递增运算符,实现自己的整型数据
项目需求
普通的自增运算符有如下案例:
int a = 0;
cout << ++a << endl; // 1
cout << a << endl; // 1
int b = 0;
cout << b++ << endl; // 0
cout << b << endl; // 1
项目需求:实现一个自定义的整形类型MyInteger
,并且同样实现上述代码的效果:
MyInteger myInt1 = 0;
cout << ++myInt1 << endl; // 1
cout << myInt1 << endl; // 1
MyInteger myInt2 = 0;
cout << myInt2++ << endl; // 0
cout << myInt2 << endl; // 1
由此可以知道我们如果要实现这个项目,需要有如下步骤:
- 自定义一个类型:
MyInteger
,以仿照int
类型 - 完成
MyInteger
类型的<<
运算符重载 - 完成
MyInteger
类型的++
运算符重载(分为前置++和后置++的实现)
项目实现
定义MyInteger
类
class MyInteger
{
public:
/// <summary>
/// MyInteger类的无参构造:定义MyInteger类型的变量(对象)且无赋初值的情况下,
/// (默认)使得其属性value值为0
/// </summary>
MyInteger()
{
value = 0;
}
/// <summary>
/// MyInteger类的有参构造:定义MyInteger类型的变量(对象)且同时赋初值的情况下,
/// 使用该初值for_value作为其属性value的值
/// </summary>
/// <param name="for_value">
/// :MyInteger类型的变量(对象)定义的同时要赋值给value的初值
/// </param>
MyInteger(int for_value)
{
this->value = for_value;
}
private:
int value;
};
以上代码是在我程序中的实际编写情况,为了让我们对代码一目了然,我去掉了一些注释,留下必要的解释,参考代码如下:
class MyInterger
{
public:
MyInterger() // 无参构造:为了确保后续我们程序中定义MyInteger类型的变量(对象)且无赋初值的情况下,
{ //(默认)使得其属性value为0
value = 0;
}
MyInteger(int for_value)// 有参构造:在程序中定义该变量(对象)且同时赋初值的情况下,
{ // 使用该初值for_value作为其属性value的值
this->value = for_value;
}
private:
int value; // 存储变量(对象)值
};
定义完MyInteger
类之后,我们对自定义的MyInteger
类进行测试,以检验我们对这个自定义的类能否仿照案例中定义int a = 0
和int b = 0
一样进行变量(对象)的定义:
void test02()
{
MyInteger myInt; // 无赋初值定义MyInteger类型变量myInt
MyInteger myInt1 = 0; // 赋初值定义MyInteger类型变量myInt1
MyInteger myInt2 = 0; // 赋初值定义MyInteger类型变量myInt2
}
编译器编译效果如下:
编译器没有报错。
说明我们MyInteger
类的定义是OK的!但是可能大家这里会有一个问题或者说是一个猜测和思考
小思考:仿照int中的"先定义,后赋值"
既然我们现在这个MyInteger
可以仿照int
定义的同时不赋初值的变量,也可以仿照int
定义的同时有赋初值的变量,那能不能仿照int
"先定义,后赋值"的这种情况呢?
这里我做了一下尝试,代码如下:
void test02()
{
MyInteger myInt; // 先定义
myInt = 10; // 后赋值
cout << myInt.value << endl; // 打印输出,以验证是否真正赋值成功
}
(为了上述代码中的第5行能够访问myInt
中的value
,我们先把MyInteger
中对value
的访问权限由private
改为public
,此处就不作代码展示了,该问题验证完之后我会将权限修改回private
)
程序运行效果如下:
程序运行后的确输出了赋值的10
…一切看起来都好像挺合理,但要执着追求事物本质的我们怎么可能这么容易就罢休呢?
我们对上面这三行代码的思考的逻辑是这样的:
如果真的是赋值成功,那么这三行代码就应该自始至终都只有一个
MyInteger
类型的变量myInt
存在,也就是说MyInteger
的构造函数只调用了一次;否则,如果
MyInteger
的构造函数调用了两次及以上就是说明上面三行代码不是一个简单的赋值过程
为了验证我们的这个猜想,我对MyInteger
类中的构造函数作了一些该进,改进后的MyInteger
类定义如下:
class MyInteger
{
public:
MyInteger()
{
cout << "无参构造调用" << endl; // 无参构造调用提示
value = 0;
}
MyInteger(int for_value)
{
cout << "有参构造调用" << endl; // 有参构造调用提示
this->value = for_value;
}
public:
int value;
};
此时再运行程序,结果如下:
发现实际上构造函数总共调用了两次,实际上test02()
中第二行代码myInt = 10;
的本质应该是这样的:
myInt = MyInteger(10);
同理第一行代码的本质是:
myInt = MyInteger();
(这里对本质的分析应用的是C++中创建对象时三种方法中的"隐式转换法"的知识)
所以test02()
也可以这样写:
void test02()
{
MyInteger myInt = MyInteger(); // 先定义
myInt = MyInteger(10); // 后赋值
cout << myInt.value << endl; // 打印输出,以验证是否真正赋值成功
}
此时程序运行后的效果是一样的:
此时这三行代码的执行流程是这样子的:
实际执行流程:
MyInteger()
调用无参构造函数,创建了一个属性value = 0
的MyInteger
匿名对象- 给这个属性
value = 0
的MyInteger
匿名对象(对应的内存空间)起了个变量名叫myInt
(注意myInt
前面的MyInteger
可以理解为是:标明myInt
这个变量名是要给MyInteger
类型的变量(对象)所使用的。注意不能去掉)MyInteger(10)
调用有参构造函数,创建了一个属性value = 10
的MyInteger
匿名对象- 用
myInt
来命名给这个属性value = 10
的MyInteger
匿名对象(对应的内存空间)- 输出此时
myInt
所命名的MyInteger
对象中的value
值
从该流程中我们可以看出:
实际上该代码并不存在赋值的过程,只是把命名一个MyInteger
对象(一块内存空间)的变量名myInt
用来命名了另一个MyInteger
对象,从而给我们造成了一种假象:让我们误以为本来的代码中的myInt = 10
这行代码是在给myInt
赋值。实际上并不是赋值!!!
本来的代码:
void test02() { MyInteger myInt; // 先定义 myInt = 10; // 后赋值 cout << myInt.value << endl; // 打印输出,以验证是否真正赋值成功 }
综上所诉,我们目前所定义的MyInteger
类是暂时无法仿照int
的"先定义,后赋值"的操作的。 只是表面上看起来好像可以实现,但本质上并不是所谓的"先定义,后赋值"的过程,解释如上。
以上问题思考和发现的关键在于:我们要意识到我们定义的是一个类,而不是一个简单的类型,“类的赋值"表面上看上去像是在"赋值”,实际上往往存在"隐式转换",而非简单的"赋值",这里我们不妨暂时认为这是C++
中的一个"缺陷",容易导致我们将其误解为"赋值"。
当然目前我们还没有学习到下一章节将要学习"赋值运算符重载",这里我猜测下一章节的这个知识就是对这个"缺陷"的优化,可以使得我们将这样的赋值操作避开"隐式转换",而做到真正意义上的赋值。让我们拭目以待!
OK,以上便是我们这个小思考的全部内容。接下来我们把程序全部修改回原来展开论述小思考前的样子,继续我们的正题:
在忽略"先定义,后赋值"这个不足的前提下,我们回忆上面在展开小思考的论述前最后提到的:
我们的仿照案例中定义int a = 0
和int b = 0
一样进行变量(对象)的定义:
void test02()
{
MyInteger myInt; // 无赋初值定义MyInteger类型变量myInt
MyInteger myInt1 = 0; // 仿照int a = 0,赋初值定义MyInteger类型变量myInt1
MyInteger myInt2 = 0; // 仿照int b = 0,赋初值定义MyInteger类型变量myInt2
}
编译器编译效果如下:
编译器没有报错。
说明我们MyInteger
类的定义是OK的!(实际上这种定义变量的同时赋初值的情况也是存在隐式转换的(MyInteger myInt = 0
<=>MyInteger myInt = MyInteger(0)
))
此时我们看一下我们项目需求:
MyInteger myInt1 = 0;
cout << ++myInt1 << endl; // 1
cout << myInt1 << endl; // 1
MyInteger myInt2 = 0;
cout << myInt2++ << endl; // 0
cout << myInt2 << endl; // 1
不仅MyInteger
类的定义要OK,后续的cout
的操作也要OK!
但当我们把cout
的操作在我们的程序中实现时,cout
的操作出现了这些报错:
cout报错
编译器报错如下:
报错的原因如下
第一个报错的原因是
<<
左移运算符不适用于我们的MyInteger
类型的变量第二个报错的原因是
++
自增(递增)运算符不适用于我们的MyInteger
类型的变量注意:这里所说的"
MyInteger
类型的变量",实际上是"MyInteger
类的对象",但为了理解方便,在后文中如不特别说明,我们都称"MyInteger
创建的对象"为"MyInteger
类型的变量"
可以看出,以上两个问题的出现是由于我们缺少对MyInteger
类的<<
和++
运算符重载,所以接下来我们逐个解决这两个问题:
解决MyInteger
类的<<
运算符重载问题
这里我们首先解决上一张图片中第54行和58行中问题,也即<<
左移运算符重载的问题:
这里涉及<<
左移运算符重载的详细内容我们在这里就不再重复了,有关的知识可以翻看上小节:4.5.2 左移运算符重载,下面我们直接就进行有关部分的代码实现:
// 类定义
class MyInteger
{
friend ostream& operator<<(ostream& cout, MyInteger& myInt); // 友元说明,使得<<运算符函数可以访问value
public:
MyInteger()
{
value = 0;
}
MyInteger(int for_value)
{
this->value = for_value;
}
private:
int value;
};
// <<运算符(重载)函数
ostream& operator<<(ostream &cout, MyInteger &myInt)
{
cout << myInt.value;
return cout;
}
// 测试函数
void test02()
{
MyInteger myInt1 = 0;
//cout << ++myInt1 << endl;
cout << myInt1 << endl; // 编译正常不报错
MyInteger myInt2 = 0;
//cout << myInt2++ << endl;
cout << myInt2 << endl; // 编译正常不报错
}
// 主函数
int main()
{
test02();
system("pause");
return 0;
}
程序运行结果如下:
程序运行正常,且结果正确。
接下来我们解决下一个问题:
解决MyInteger
类的++
运算符重载问题
该问题的解决即是我们本节内容的重点:
我们把上一张图片中的第62行和66行代码注释解除,会发现这两行代码报错如下:
注意:此时这两行代码报错的波浪线位置是出现在"++"下面报错:没有与这些操作数匹配的 “++” 运算符
报错的原因我们也很熟悉了,根据前两小节的经验可以知道,这是由于++
运算符无法识别MyInteger
类型的变量所导致的,或者说这是由于MyInteger
类本身没有对应的++
运算符操作函数所导致的,所以我们需要为这个MyInteger
类的++
运算符编写相应操作函数,使得该类型所定义的变量可以进行++
运算。这里我们要实现的++
运算操作有两个,一个是要服务于MyInteger
类型变量myInt
的前置++
操作:++myInt
,还要一个是要服务于myInt
的后置++
操作:myInt++
,我们逐个来实现:
实现MyInteger
类型变量的前置++操作++myInt
成员函数实现
我们先通过成员函数来实现,即在MyInteger
类中写这个函数。
首先我们是希望++
操作完成之后,myInt
中的value
加1
的,也就是说我们希望++
运算符操作函数调用完成后,myInt.value
的值加1
,由此我们先在MyInteger
类中写出能完成这个"加1
功能"的函数基本框架:
// MyInteger类中实现(public权限):
void operator++()
{
value++; // 写成value = value + 1、value += 1、++value都没有问题,保证这行代码执行结束后value增加1即可
}
这里大家可能会有疑问:编译器要如何辨别我们所写的这个函数是服务于前置++
还是后置++
?
补充:编译器区分前置和后置++
运算符操作函数的方法
编译器区分这两类运算符操作函数的方法就是通过函数的形参列表中有无占位参数来确定的:
1.如果形参列表中没有占位参数,如本案例中上面所展示的代码:
函数返回值类型 operator++() // 形参列表无占位参数
此时编译器就认为该函数是服务于前置
++
的运算符操作函数2.如果形参列表中有占位参数,如下:
函数返回值类型 operator++(int) // 形参列表有占位参数
此时编译器就认为该函数是服务于后置
++
的运算符操作函数
OK,这是关于编译器如何区分前置和后置++
运算符操作函数的知识补充,我们继续刚才的内容:
上面我们已经写出了运算符操作函数的基本框架:
// MyInteger类中实现(public权限):
void operator++()
{
value++; // 写成value = value + 1、value += 1、++value都没有问题,保证这行代码执行结束后value增加1即可
}
这时我们回到测试函数中查看代码:
发现编译器报错!注意:在此之前报错的波浪线位置是出现在"++“下方的,但是现在转移到了”<<"下方
报错原因解释:此时<<
报错原因在于++myInt
的操作是调用了我们上面的void operator++()
函数,这个函数是的确是实现了myInt.value
的加1
,但是它的返回值的是void
,也就是说++myInt
操作结束后++myInt
整体相当于一个void
,所以此时的cout
就相当于对一个void
操作:cout << void
,而我们前面写的<<
运算符的重载函数要求<<
的右边是一个MyInteger
类型的变量,这里编译器肯定不知道<<
右边是void
的情况要咋整,除非我们为这种<<
右边是void
的情况再写一个MyInteger
类的<<
运算符重载函数(即这个函数的形参有一个void
类型),但这样意义何在?写了这个函数,然后在这个函数里面操作void
吗?不能这样,也没有意义这样做对吧!
解决报错:我们要的是cout
执行的时候输出myInt.value
,所以这里解决问题的关键不在于实现cout << void
的运算符重载函数,而是在于想办法让cout << ++myInt
能够符合我们前面所写的那个<<
运算符右边是MyInteger
类型的<<
运算符重载函数!
所以这就要求++myInt
操作之后++myInt
是个MyInteger
类型,也就是说++
运算符重载函数的返回值类型应该是MyInteger
,并且返回的是myInt
这个变量本身(只有返回myInt
本身才能用于cout
输出myInt
中的属性值,如果返回的不是myInt
本身,cout
的输出是无意义的)。由此我们对++
运算符重载函数进行改进,改进后的函数代码如下:
// MyInteger类中实现(public权限):
MyInteger& operator++() // 以引用"&"的方式进行返回
{
value++; // 先进行++运算,使得value值+1
return *this; // 返回myInt变量本身
}
这里的改进相信大家不免还是有疑惑,下面我就对这里面改进的细节作一下描述和解释:
引用返回
MyInteger&
:保证++
操作(即调用++
运算符操作函数)之后,返回的仍然是调用该函数的变量myInt
本身。解释:在"以引用
&
的方式返回"的这种情况下,++myInt
操作执行完成后,配合return *this
,++myInt
整体就等价于原来的那个myInt
,即++myInt
在执行完成++
操作后,其整体就相当于是一个变量名,并且这个变量名在内存中所命名的内存空间,与++
操作执行前的myInt
在内存中所命名的内容空间是同一块。对这个执行流程的理解逻辑我们在"4.5.2 左移运算符重载——关于cout的补充知识"中做过展开,下面我展示一下当时这部分内容知识的简略图给大家参考理解,如下图。若需详细了解或复习请转至"4.5.2 左移运算符重载"。
简略图(着重看红框部分):
这里返回引用
&
的方式就可以保证这样的场景能够适用:++(++myInt)
,实际上这也是链式编程的思想。而如果这里我们不采用返回引用
MyInteger&
的方式,而是直接返回MyInteger
,那么++(++myInt)
操作的结果就会与int
类型的变量执行相同操作时产生的结果存在差异。这部分内容又是一个可以展开补充的小知识,由于这部分内容较多,我在我的这篇另外的博客中进行展开:补充知识
return *this
:返回变量(对象)本身。因为在MyInteger
类内部的成员函数中,this
是指向调用这些函数的变量(对象)本身的指针。解释:在本例中
this
就是指向myInt
的指针,this
中存储的就是myInt
这个变量所对应的内存空间的地址,而*this
就是myInt
本身,所以这里这个运算符操作函数返回*this
,就是在返回调用这个成员函数的变量(对象)myInt
的本身。也就是说本来是myInt
调用了这个成员函数,而在这个函数内部*this
就是myInt
,在函数执行完成后return *this
,就是返回了myInt
)OK,这部分是对大家可能存在疑惑的地方的一个描述和解释。
那么我们的代码改进完成之后,当我们再次回到测试函数中查看代码时:
可以看到此时编译器已经对第68行的代码不再报错,程序执行的效果如下图:
实现了我们项目需求的前半部分,仿照实现了int
类型的++
自增(递增)运算符的前半部分功能:前置++
:
此时代码整体如下:
#include <iostream>
#include<string>
#include<stdlib.h>
using namespace std;
class MyInteger
{
friend ostream& operator<<(ostream& cout, const MyInteger& myInt);
public:
/// <summary>
/// MyInteger类的无参构造:为了确保程序中定义MyInteger类型的变量(对象)且无赋初值的情况下,
/// (默认)使得其属性value值为0
/// </summary>
MyInteger()
{
value = 0;
}
/// <summary>
/// MyInteger类的有参构造:在程序中定义MyInteger类型的变量(对象)且同时赋初值的情况下,
/// 使用该初值for_value作为其属性value的值
/// </summary>
/// <param name="for_value">
/// :MyInteger类型的变量(对象)定义的同时要赋值给value的初值
/// </param>
MyInteger(int for_value)
{
this->value = for_value;
}
MyInteger& operator++()
{
value++; // 写成value = value + 1、value += 1、++value都没有问题,保证这行代码执行结束后value增加1即可
return *this;
}
private:
int value;
};
ostream& operator<<(ostream& cout, const MyInteger& myInt)
{
cout << myInt.value;
return cout;
}
// 测试函数
void test02()
{
MyInteger myInt1 = 0;
cout << ++myInt1 << endl; // 1
cout << myInt1 << endl; // 1
MyInteger myInt2 = 0;
//cout << myInt2++ << endl; // 0
//cout << myInt2 << endl; // 1
}
int main()
{
test02();
system("pause");
return 0;
}
全局函数实现
当然对于前置++
运算符操作函数我们也可以通过全局函数来实现,其实现代码如下
MyInteger& operator++(MyInteger& myInt)
{
myInt.value++;
return myInt;
}
代码内容基本不变,只是函数的形参发生了变化(注意要以引用的方式声明形参才能保证传入到函数的是我们要自增的对象/变量的本体)。
另外如果类定义中的属性是私有属性,我们还需将上述代码在MyInteger
类中声明为友元。最终整体代码如下:
#include <iostream>
#include<string>
#include<stdlib.h>
using namespace std;
class MyInteger
{
friend MyInteger& operator++(MyInteger& myInt);
friend ostream& operator<<(ostream& cout, const MyInteger& myInt);
public:
MyInteger()
{
value = 0;
}
MyInteger(int for_value)
{
this->value = for_value;
}
private:
int value;
};
ostream& operator<<(ostream& cout, const MyInteger& myInt)
{
cout << myInt.value;
return cout;
}
MyInteger& operator++(MyInteger& myInt) // 全局函数实现前置++运算符操作函数
{
myInt.value++;
return myInt;
}
void test()
{
MyInteger myInt1 = 0;
cout << ++myInt1 << endl; // 1
cout << myInt1 << endl; // 1
// MyInteger myInt2 = 0;
// cout << myInt2++ << endl; // 0
// cout << myInt2 << endl; // 1
}
int main()
{
test();
system("pause");
return 0;
}
实现MyInteger
类型变量的后置++操作myInt++
成员函数实现
首先我们根据前面提到的编译器是如何区分前置和后置++
运算符操作函数的知识,我们不妨先定义后置++
的运算符操作函数的函数头:void operator++(int)
接下来我们讨论后置++
运算符操作函数的函数体实现:对于后置++
,我们是希望myInt
先执行相应的操作之后,最后才来自增加1。
那么能不能是如下的这种方式呢?——先return
返回,返回之后再来++
?例如下面的代码
void operator++(int)
{
// 先返回结果
return ...
// 后自增加1
value++;
}
这样显然是不允许的,因为这样的代码函数直接return
返回,后面的value++
根本就无法执行,因此这样无法达到我们"先执行相应的操作之后,最后才来自增加1"的目的。
那么究竟要怎么写才能实现我们想要的效果呢?
既然我们要返回的是自增前的结果,那不妨我们在自增前先进行一份拷贝,然后在自增后将这份自增前的拷贝进行return
返回,即
- 先拷贝一份变量/对象(记录自增前的变量/对象)
- 变量/对象属性
++
- 返回
++
前的那份拷贝变量/对象例如某个变量/对象的属性值为0,那么我们先拷贝这个0,再让这个变量/对象的属性值
++
(这时这个变量/对象的属性值已经变成了1)然后return
返回0
实现代码如下
void operator++(int)
{
// 先拷贝一份自增前的变量/对象
MyInteger temp = *this; // 这里会调用拷贝构造函数
// 后自增加1
value++;
// 最后返回自增前的变量/对象
return temp;
}
因为我们return
的temp
是一个MyInteger
对象,所以这个函数的返回值类型应该为MyInteger
,那么这个MyInteger
要不要以引用的方式返回呢,即MyInteger&
?
答案是不要!因为我们的temp
是创建在这个++
运算符操作函数内部的,是一个局部变量,当我们这个函数执行结束后,这个temp
所占用的内存空间就不再属于我们这个程序了,如果是以引用的方式返回,那么接下来当程序执行回到这个函数的起始调用位置时,我们如果对这个引用返回的变量/对象进行操作就是非法访问了!
所以我们这里不返回引用,即返回值类型我们写MyInteger
即可,这样在返回temp
时会根据temp
拷贝一份拷贝体作为返回,这样接下来当程序执行回到这个函数的起始调用位置时,我们所要操作的这个变量/对象就是temp
的拷贝体,也就是自增前的myInt
。
所以前置++
是引用的方式进行返回,而后置++
则不需要(或者说不可以)以引用的方式返回。
由于后置++
返回的是MyInteger
类型对象,所以能够符合我们前面缩写的<<
运算符操作函数的形参类型,所以后置++
后的结果也能够调用<<
运算符操作函数。
最终代码的实现效果如下:
可以看到这样就完美地实现了我们前面的项目需求了!、
补充说明(关于链式操作)
由于后置++
运算符操作函数返回的是拷贝体,因而其无法完成链式操作,例如(myInt++)++
,但实际上这种方式对于int类型的变量本身也是不允许的,例如下面的代码
当我们写到这样的代码时,编译器会报错。
所以实际上对于(myInt++)++
的实现是没有多大意义的,因此我们没有必要对后置++
考虑其链式操作的实现。
到这里,MyInteger
类的定义如下:
class MyInteger
{
friend ostream& operator<<(ostream& cout, const MyInteger& myInt);
public:
MyInteger()
{
value = 0;
}
MyInteger(int for_value)
{
this->value = for_value;
}
MyInteger& operator++()
{
value++;
return *this;
}
MyInteger operator++(int)
{
MyInteger temp = *this;
value++;
return temp;
}
private:
int value;
};
测试函数如下:
// 测试函数
void test02()
{
MyInteger myInt1 = 0;
cout << ++myInt1 << endl; // 1
cout << myInt1 << endl; // 1
MyInteger myInt2 = 0;
cout << myInt2++ << endl; // 0
cout << myInt2 << endl; // 1
}
全局函数实现
后置++
运算符操作函数的实现代码如下:
MyInteger operator++(MyInteger& myInt, int)
{
MyInteger temp = myInt;
myInt.value++;
return temp;
}
可以看到与成员函数实现相比,函数体内容也基本一致,全局函数实现的差别仅在形参(注意形参声明为引用)。
另外如果类定义中的属性是私有属性,我们还需将上述代码在MyInteger
类中声明为友元。最终整体代码如下:
#include <iostream>
#include<string>
#include<stdlib.h>
using namespace std;
class MyInteger
{
friend MyInteger& operator++(MyInteger& myInt);
friend MyInteger operator++(MyInteger& myInt, int);
friend ostream& operator<<(ostream& cout, const MyInteger& myInt);
public:
MyInteger()
{
value = 0;
}
MyInteger(int for_value)
{
this->value = for_value;
}
private:
int value;
};
ostream& operator<<(ostream& cout, const MyInteger& myInt)
{
cout << myInt.value;
return cout;
}
MyInteger& operator++(MyInteger& myInt) // 全局函数实现前置++运算符操作函数
{
myInt.value++;
return myInt;
}
MyInteger operator++(MyInteger& myInt, int) // 全局函数实现后置++运算符操作函数
{
MyInteger temp = myInt;
myInt.value++;
return temp;
}
void test()
{
MyInteger myInt1 = 0;
cout << ++myInt1 << endl; // 1
cout << myInt1 << endl; // 1
MyInteger myInt2 = 0;
cout << myInt2++ << endl; // 0
cout << myInt2 << endl; // 1
}
int main()
{
test();
system("pause");
return 0;
}