• 编译器默认生成六个成员函数方法


    1】空类为什么可以创建对象呢?
    
    示例代码如下:
    
    
    1 class Test
    2 {
    3 };
    4 void main()
    5 {
    6     Test t1;
    7     cout<<sizeof(Test)<<endl;  //1
    8 }
    
    让我们先看看这个例子。既然都没有构造函数,怎么实现对象t1的构建呢?
    
    哦,经过大脑的回旋式搜索,忆得有一本书上说过,当用户定义一个空类(如上)时,编译器就会为这个类默认生成六个方法。
    
    既然这是编译器完成的工作,那我们只要知道是那些方法就好了,其余就学习编译器的结构以及原理了。
    
    那么,编译器生成了那六个方法:示例代码如下:
    
    
     1 class Empty
     2 {
     3 public:
     4     Empty();                      //默认构造方法
     5     Empty(const Empty &);         //拷贝构造函数
     6     ~Empty();                     //析构函数
     7     Empty &operator=(const Empty &);   //赋值函数
     8     Empty *operator &();               //取地址
     9     const Empty * operator&() const;   //常对象取地址
    10 };
    
    OK,这就是默认生成的那六个方法。其中前四个是经常谈及到的,也是平常定义一个类时,尤其要慎重考虑的。
    
    到这里,也许有人还看出了点问题。那就是为什么空类的大小是1呢??呵呵~~编译器搞的鬼?其实也不是随随便便搞的鬼,我们说:存在即是合理的!这样做肯定有它的道理。
    
    大家试想一个极端问题,现在还是上面这个空类,我们定义一个语句:Test  ar[10];一个对象数组。
    
    好啦,如果sizeof(Test)==0,那么我们如何区分数组的十个元素??你想想这不是狭隘的表现吗?
    
    所以说,为了更完善,更健壮,更伟大。编译器插入这个字节,是为了再使用这个类定义多个对象的时候能保证每个对象有自己的地址。
    
    另外,大家看看这个例子:
    
    
    1 A *pa1,pa2;
    2 pa1 = new A();
    3 pa2 = new A();
    4 ..
    5 if(pa1 == pa2)    //如果不分配内存,这个比较就会失去意义
    6 {
    7 }
    
    【2】构造函数注意哪些知识点?
    
    (1)构造函数
    
    构造函数是一种特殊的方法,主要用来在创建对象时初始化对象,即为对象的属性(数据成员)赋初始值,总与new运算符一起使用在创建对象的语句中。
    
    在C++重载的机制下,一个类可以有多个构造函数,可根据其参数个数的不同或参数类型的不同或参数顺序的不同来区分它们,即构造函数的重载。
    
    (2)构造函数注意事项:
    
    <1>构造函数的函数名必须与类名相同,而且没有返回值,更不能用void来修饰。默认访问权限是public的,并且inline函数【常识】
    
    <2>构造函数允许重载。【各个不同的构造函数创建的对象就是所谓的天生不同性】
    
    <3>构造函数不能被直接调用,必须通过new运算符在创建对象时才会自动调用。
    
    <4>当一个类没有定义构造函数时,编译器会为每个类添加一个默认的构造函数。
    
    <5>在一个类中,只要有用户自定义的一个构造函数,那么这个类的默认构造函数就不再存在。
    
    那么也就意味着,欲实现想默认构造函数那样创建对象的形式,必须另外添加一个默认构造函数,或者用户定义一个复合默认构造函数。
    
    准确理解请看以下示例代码:
    
     1 /*
     2  *默认构造函数创建对象
     3  */
     4 class Test
     5 {
     6 private:
     7     int a;
     8 };
     9 void main()
    10 {
    11     Test t1;  //默认构造函数创建对象
    12 }
    
     1 /*
     2  *自定义构造函数
     3  */
     4 class Test
     5 {
     6 private:
     7     int a;
     8 public:
     9     Test(int x):a(x)
    10     {}
    11 };
    12 void main()
    13 {
    14 //  Test t1;  //error!!编译器提示:no appropriate default constructor available
    15     Test t2(100);  //OK 因为有相应类型的构造函数(自定义构造函数)
    16 }
    
     1 /*
     2  *复合默认构造函数
     3  */
     4 class  Test
     5 {
     6 private:
     7     int a;
     8 public:
     9     //Test(){};     //error!!  编译时出错,因为下面的这个是复合默认构造函数,二者冲突
    10     Test(int x=10):a(x){};
    11 };
    12 void main()
    13 {
    14     Test  t1;      //OK 因为构造函数有默认值
    15     Test  t2(100);  //OK  因为有相应类型的构造函数 
    16 }
    
    <6>构造函数一般不建议定义为私有的,因为在外部无法实现对象的创建。但是,特殊需要的情况下也是可以的这样实现的。
    
    <7>构造函数有两种方式实现对数据成员的初始化。
    
    1:使用初始化列表进行初始化【第五点中示例代码可见】
    
    2:在函数体中进行初始化
    
    <8>在用默认构造函数创建对象时,如果创建的是全局对象或静态对象,则对象的位模式全为 0,否则,对象值是随机的。
    
    <9>基类构造函数负责构建基类的对象,派生类的构造函数负责构建派生类的对象。派生类对象创建是由基类开始进行的。
    
    <10>构造函数不可以声明为const,也是完全没有必要的
    
    <11>注意分清楚对象与函数声明问题。示例代码如下:
    
    
     1 class  Test
     2 {
     3 private:
     4     int a;
     5 public:
     6     Test(){};    
     7 };
     8 void main()
     9 {
    10     Test  t1;     //对象?
    11     Test  t2();   //对象?函数?
    12 }
    
    注意:第十一行:编译器是以函数声明进行编译的,不是一个对象!
    
    【3】析构函数注意哪些知识点?
    
    (1)析构函数
    
     我们已经了解了C++的编程哲学观是面向对象的,那么程序在运行时,创建了很多的对象,而这些对象在当初系统创建时,是为各自都分配有一定的内存空间的。
    
    现在,程序要结束了!我们就要释放我们所建立的这些对象所占用的内存资源。而析构函数就是完成这些善后工作的。
    
    (2)析构函数注意事项:
    
    <1>构造函数的函数名必须与类名相同,与构造相反再加一个非(~)。而且无参数没有返回值,更不能用void来修饰。
    
    默认访问权限是public的,并且inline函数【常识】
    
    <2>析构函数不可以重载,一个类中只允许有一个析构函数
    
    <3>建立对象时若用new开辟了一片内存空间,应在退出前在析构函数中用delete全部释放
    
    <4>析构函数仅仅只是一个普通成员函数
    
    <5>new 与 delete操作符详解
    
    请看下面的示例代码以及说明:
    
    new操作符使用示例:
    
    Test  *ptr = new Test();
    这一条语句,new操作符完成了两件事。
    
    1:分配足够的内存以便容纳所需类型的对象。
    
    2:调用构造函数初始化内存中的对象。
    
    而且,你始终记住,new操作符的使命,或者说赋予它的能力就是这么大,只完成这两件事情,不能以任何方式改变它的行为。
    
    delete操作符使用示例:
    
    delete  ptr;
    这一条语句,delete操作符完成了两件事。
    
    1:调用对象的析构函数,释放对象申请的堆内存。
    
    2:释放对象本身的内存,彻底释放本次申请的资源。
    
    另外,请看如下两段代码:
    
    代码1:
    
    
     1 #include<iostream>
     2 using namespace  std;
     3 class Test
     4 {
     5 public:
     6     Test()
     7     {
     8         p = new char[1024];
     9     }
    10     ~Test()
    11     {
    12         cout<<"deconstructor"<<endl; 
    13         delete []p; 
    14         p = NULL;
    15     }
    16 private:
    17     char *p;
    18 };
    19 void main()
    20 {
    21     Test  *pa = new Test();
    22     pa->~Test();  //? ? ?  
    23 }
    
    代码2:
    
    
     1 #include<iostream>
     2 using namespace  std;
     3 class Test
     4 {
     5 public:
     6     Test()
     7     {
     8         p = new char[1024];
     9     }
    10     ~Test()
    11     {
    12         cout<<"deconstructor"<<endl; 
    13         delete []p; 
    14         p = NULL;
    15     }
    16 private:
    17     char *p;
    18 };
    19 void main()
    20 {
    21     Test  *pa = new Test();
    22     delete pa;  //? ? ?  
    23 }
    
    分析:注意每个示例的第22行:
    
    第一个:仅仅调用了析构函数,析构函数释放了申请的堆内存。而对象本事的内存,明显是由系统回收了。
    
    第二个:delete就隐式的调用了析构函数,并且释放了pa所指向的对象本身内存。最后main函数退出前,摧毁pa指针。
    
    其实,这个道理很简单的。举个现实的例子:见过盖房子和拆房子吧?申请内存就像买地基,构建对象就类似盖房子,析构就像拆房子,而pa就像你家的房地产证。
    
    pa指向当初买的地盘,那肯定是比你盖房子的那块地皮要大得多!
    
    所以说这也就是问题的关键,我们要归还的不仅仅是你房子占的那么大面积,而是要全部释放掉你当初申请的那么大块的面积。
    
    【4】拷贝构造函数注意哪些知识点?
    
    (1)为什么需要拷贝构造函数?
    
    因为我们想实现用一个已知对象去创建一个与它完全相同的新对象
    
    (2)拷贝构造函数有什么特点?
    
    <1>函数名与类名相同,并且没有返回值类型
    
    <2>有且仅有一个参数,并且是同类已知对象的引用
    
    <3>每个类必有一个拷贝构造函数,如果programer没有定义,系统会添加默认拷贝构造函数
    
    (3)拷贝构造的参数为什么是对象引用?
    
    如果不是的话,将导致无限递归.....
    
    (4)拷贝构造函数一般在什么时候使用?
    
    <1>声明一个新的对象时,用已知对象初始化新对象。
    
    示例代码如下:
    
    
     1 #include<iostream>
     2 using namespace std;
     3 
     4 class  Test
     5 {
     6 private:
     7     int a;
     8 public:
     9     Test(int x=0):a(x)  
    10     {
    11         cout<<"construction"<<endl;
    12     } 
    13     Test(const Test & t)
    14     {
    15         cout<<"Copy  construction"<<endl;
    16         a=t.a;
    17     }
    18 };
    19 
    20 void main()
    21 {
    22     Test  t1;      //调用构造函数
    23     Test  t2(t1);  //调用拷贝构造函数
    24     Test  t3 = t2;   //调用拷贝构造函数
    25     } 
    26 /*
    27 construction
    28 Copy  construction
    29 Copy  construction
    30 */
    
    <2>当一个已知对象作为一个实参传递给一个函数的形参时,在用实参对象初始化形参对象时,需要调用拷贝构造函数。
    
    <3>当对象作为一个函数的返回值时,要创建临时对象,临时对象的初始化是调用拷贝构造函数进行的。
    
    关于<2>,<3>点示例代码如下:
    
    
     1 #include<iostream>
     2 using namespace std;
     3 
     4 class  Test
     5 {
     6 private:
     7     int a;
     8 public:
     9     Test(int x = 0):a(x)  
    10     {
    11         cout<<"construction"<<endl;
    12     } 
    13     Test(const Test & obj)
    14     {
    15         cout<<"Copy  construction"<<endl;
    16         a = obj.a;
    17     }
    18 };
    19 
    20 Test  Fun(Test  t)
    21 {
    22      return t;
    23 }
    24 
    25 void main()
    26 {
    27     Test  t1;      //调用构造函数
    28     Test  t2(t1);  //调用拷贝构造函数
    29     Fun(t2);      //两次调用拷贝构造函数
    30 } 
    31 
    32 //the  result  of  this:
    33 /*
    34 construction
    35 Copy  construction
    36 Copy  construction
    37 Copy  construction
    38 */
    
    <4>在以下两种方式下也是应用拷贝构造函数的
    
    1:在初始化顺序容器中的元素时
    
    2:根据元素初始化列表初始化数组元素  
    
    (5)什么是浅拷贝?什么是深拷贝?
    
    其实,浅拷贝深拷贝是很简单的问题。这样说话有点欠拍砖!因为会的人什么都觉得简单。呵呵!请看下面的分析:
    
    想象一下:假如一个类中的数据成员有一个是指针类型的,那么,用户创建一个对象,系统就要为这个对象的指针成员对应的分配一块内存。
    
    而如果你仍想用这个已经创建的对象通过拷贝构造函数去创建一个新的对象,问题就出现了?什么问题呢?就是你问的问题(嘿嘿~~)。
    
    如果你让新对象的指针成员直接赋值为已知对象的指针成员值,就意味着两个对象指向了同一块内存。
    
    那样的话在析构对象时,因为有一个先后顺序之分,就会对同一块内存释放两次,就会导致系统崩溃!这就是所谓的浅拷贝。
    
    那深拷贝呢?也就是解决了如上的麻烦。
    
    其解决方案就是重新为新对象的指针成员开辟空间,然后把已知对象的指针所指内容拷贝过去,实现内容的完全一致。并且保证各自独立。
    
    浅拷贝示例代码如下:
    
    
     1 #include<iostream>
     2 #include<assert.h>
     3 #include<string.h>
     4 using namespace std;
     5 class  String
     6 {
     7 public:
     8     String(const char *str=NULL);
     9     String(const String &other);
    10     ~String();
    11 private:
    12     char  *m_data;
    13 };
    14 
    15 String::String(const char *str)
    16 {
    17     if(str==NULL)
    18     {
    19         m_data=new char[1];
    20         assert(m_data!=NULL);
    21         *m_data='';
    22     }
    23     else
    24     {
    25         int length=strlen(str);
    26         m_data=new char[length+1];
    27         assert(m_data!=NULL);
    28         strcpy(m_data,str);
    29     }
    30 }
    31 
    32 String::String(const String &other)
    33 {
    34     m_data=other.m_data;
    35 }
    36 
    37 String::~String()
    38 {
    39     delete []m_data;
    40 }
    41 
    42 void main()
    43 {
    44     String  str1("liuyong");
    45     String  str2(str1);
    46 }
    
    注意,浅拷贝也是系统默认拷贝构造函数的实现方式,因为存在这种缺陷,所以才有了深拷贝的进一步完善。
    
    深拷贝示例代码如下:
    
    1 String::String(const String &other)
    2 {
    3     int length=strlen(other.m_data);
    4     m_data=new char[length+1];
    5     assert(m_data!=NULL);
    6     strcpy(m_data,other.m_data);
    7 }
    
    (6)拷贝构造函数一般为共有的。
    
    【5】赋值函数注意哪些知识点?
    
    (1)什么是赋值函数?
    
    一个类中赋值运算符的重载方法即就是赋值构造函数
    
    (2)为什么需要赋值函数?
    
    当用户使用内置数据类型时,可以进行顺利的运算操作。
    
    示例代码如下:
    
    1 void main()
    2 {
    3     int a = 10, b = 20, sum;
    4     sum = a + b;
    5     cout<<sum<<endl;
    6 }
    而如果Programer自己定义新的类型时,由于系统没有实现相关运算符重载函数,所以是无法进行相关的操作。
    
    示例代码如下:
    
    
     1 class Complex //复数类
     2 {
     3 public:
     4     double real;//实数
     5     double imag;//虚数
     6     Complex(double real=0,double imag=0)
     7     {
     8         this->real=real;
     9         this->imag=imag;
    10     }
    11 };
    12 
    13 void main()
    14 {
    15     Complex com1(10,20),com2(1,2),sum;
    16     sum = com1 + com2;             //error!!编译错误
    17 }
    
     那么,为了处理这种问题,C++可以使用运算符重载机制,实现运算符重载函数。即就是赋值函数的由来。
    
    (3)运算符重载函数需要注意哪些?
    
    <1>运算符重载函数其函数名字规定为operator后紧跟重载运算符。比如:operator+(),operator*()等。
    
    现在我们给上述程序声明一个加法运算符的重载函数用于完成复数的加法运算:
    
    示例代码如下:
    
    
     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Complex //复数类
     5 {
     6 public:
     7     double real;//实数
     8     double imag;//虚数
     9     Complex(double real=0,double imag=0)
    10     {
    11         this->real=real;
    12         this->imag=imag;
    13     }
    14 };
    15 
    16 Complex operator+(Complex com1,Complex com2)  //实现运算符重载函数
    17 {
    18     return Complex(com1.real+com2.real,com1.imag+com2.imag);
    19 }
    20 
    21 void main()
    22 {
    23     Complex  com1(10,10),com2(20,20),sum;
    24     sum = com1 + com2;    //或sum=operator+(com1,com2)
    25 
    26     cout<<"sum的实数部分为"<<sum.real<<endl;
    27     cout<<"sum的虚数部分为"<<sum.imag<<"i"<<endl;
    28 }
    29 /*
    30  *sum的实数部分为30
    31  *sum的虚数部分为30i
    32  */
    
    如果仔细观察的话,上面的示例是有很多问题的。
    
    因为那个运算符重载函数是全局的,那也就意味着,如果类中的数据成员不是public,这个方法就无能为力!
    
    为了解决这个问题:“解铃仍需系铃人”C++不是有友元函数吗?OK,看下面的处理方案。
    
    友元函数重载双目运算符。示例代码如下:
    
    
     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Complex //复数类
     5 {
     6 private://私有
     7     double real;//实数
     8     double imag;//虚数
     9 
    10 public:
    11     Complex(double real=0,double imag=0)
    12     {
    13         this->real = real;
    14         this->imag = imag;
    15     }
    16 
    17     friend Complex operator+(Complex com1,Complex com2);      //友元函数重载双目运算符+
    18     void showSum();
    19 };
    20 
    21 Complex  operator+(Complex com1,Complex com2)        //友元运算符重载函数
    22 {
    23     return Complex(com1.real+com2.real,com1.imag+com2.imag);
    24 }
    25 
    26 void Complex::showSum()
    27 {
    28     cout<<real;
    29     if(imag>0)
    30         cout<<"+";
    31     if(imag!=0)
    32         cout<<imag<<"i"<<endl;
    33 }
    34 
    35 void main()
    36 {
    37     Complex com1(10,10),com2(20,-20),sum;
    38     sum = com1 + com2;    //或sum=operator+(com1,com2)
    39     sum.showSum();        //输出复数相加结果
    40 }
    41 
    42 /*
    43  *30-10i
    44  */
    
    友元函数重载单目运算符。示例代码如下:
    
    
     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Point    //坐标类
     5 {
     6 private:
     7     int x;
     8     int y;
     9 public:
    10     Point(int x,int y)
    11     {
    12         this->x=x;
    13         this->y=y;
    14     }
    15 
    16     friend void operator++(Point& point);//友元函数重载单目运算符++
    17     void showPoint();
    18 };
    19 
    20 void operator++(Point& point)          //友元运算符重载函数
    21 {
    22     ++point.x;
    23     ++point.y;
    24 }
    25 
    26 void Point::showPoint()
    27 {
    28     cout<<"("<<x<<","<<y<<")"<<endl;
    29 }
    30 
    31 void main()
    32 {
    33     Point point(10,10);
    34     ++point;           //或operator++(point)
    35     point.showPoint(); //输出坐标值
    36 }
    37 /*
    38  *<11,11>
    39  */
    
    注意:像赋值运算符=、下标运算符[]、函数调用运算符()等是不能被定义为友元运算符重载函数。
    
    <2>运算符重载函数可以返回任何类型,甚至是void,但通常返回类型都与它所操作的类类型一 样,这样可以使运算符使用在复杂的表达式中。
    
    比如把上述双目运算符重载函数示例代码中main()主函数里的com1+com2改为 com1+com2+com2,那么结果又会不一样了。
    
    <3>对于成员函数重载运算符而言,双目运算符的参数表中仅有一个参数,而单目则无参数。
    
    示例代码如下:
    
    
     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Complex //复数类
     5 {
     6 private://私有
     7     double real;//实数
     8     double imag;//虚数
     9 
    10 public:
    11     Complex(double real=0,double imag=0)
    12     {
    13         this->real=real;
    14         this->imag=imag;
    15     }
    16 
    17     Complex operator+(Complex com1);//成员函数重载双目运算符+
    18     void showSum();
    19 };
    20 
    21 Complex Complex::operator+(Complex com1)
    22 {
    23     return Complex(real+com1.real,imag+com1.imag);
    24 }
    25 
    26 void Complex::showSum()
    27 {
    28     cout<<real;
    29     if(imag>0)
    30         cout<<"+";
    31     if(imag!=0)
    32         cout<<imag<<"i"<<endl;
    33 }
    34 
    35 void main()
    36 {
    37     Complex com1(10,10),com2(20,-20),sum;
    38     sum = com1 + com2;    //或sum=com1.operator+(com2)
    39     sum.showSum();     //输出复数相加结果
    40 }
    41 /*
    42  *30-10i
    43  */
    
    同样是重载,为什么与友元函数在参数的个数上会有所区别呢?原因在于友元函数没有this指针。
    
    <4>C++中只能对已有的C++运算符进行重载,不允许用户自己定义新的运算符。
    
    <5>C++中绝大部分的运算符可重载,除了成员访问运算符.,成员指针访问运算符.*,作用域运算符::,长度运算符sizeof以及条件运算符?:。
    
    <6>重载后不能改变运算符的操作对象(操作数)的个数。如:"+"是实现两个操作数的运算符,重载后仍然为双目运算符。
    
    <7>重载不能改变运算符原有的优先级。
    
    <8>重载不能改变运算符原有结合的特性。比如:z=x/y*a,执行时是先做左结合的运算x/y,重载后也是如此,不会变成先做右结合y*a。
    
    <9>运算符重载不能全部是C++中预定义的基本数据,这样做的目的是为了防止用户修改用于基本类型数据的运算符性质。
    
    <10>从上述的示例中可以看到双目运算符可以被重载为友元函数也可以重载为成员函数。
    
    但有一种情况,只能使用友元函数,是什么情况呢?我举个例子,示例代码如下:
    
    
     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Complex //复数类
     5 {
     6 private://私有
     7     double real;//实数
     8     double imag;//虚数
     9 
    10 public:
    11     Complex(double real=0,double imag=0)
    12     {
    13         this->real=real;
    14         this->imag=imag;
    15     }
    16     Complex operator+(int x);
    17 };
    18 
    19 Complex Complex::operator+(int x)
    20 {
    21     return   Complex(real+x,imag);
    22 }
    23 
    24 void main()
    25 {
    26     Complex com1(5,10),total;
    27     total = com1 + 5;   //OK  
    28 //  total = 5 + com1;   //编译error!!!  注意:com1+5 与 5+com1是两个不同的概念
    29 }
    
    因为左操作数5不是该复数类的对象,不能调用相应的成员函数Complex operator+(int x),所以编译错误。
    
    但如果我们定义一下两个友元函数就能解决上述的问题:
    
    1 friend Complex operator+(Complex com1,int x);
    2 
    3 friend Complex operator+(int x,Complex com1);
    示例代码如下:
    
    
      1 #include <iostream>
      2 using namespace std;
      3 
      4 class Complex //复数类
      5 {
      6 private://私有
      7     double real;//实数
      8     double imag;//虚数
      9 public:
     10     Complex(double real=0,double imag=0)
     11     {
     12         this->real=real;
     13         this->imag=imag;
     14     }
     15     Complex operator+(Complex com1); //成员函数重载双目运算符+
     16     //或friend Complex operator+(Complex com1,Complex com2);  //友元函数重载双目运算符+
     17     friend Complex operator+(Complex com1,int x);             //友元函数重载双目运算符+
     18     //或Complex operator+(int x);
     19     friend Complex operator+(int x,Complex com1);           //友元函数重载双目运算符+
     20     void showSum();
     21 };
     22 
     23 Complex Complex::operator+(Complex com1)
     24 {
     25     return Complex(real+com1.real,imag+com1.imag);
     26 }
     27 
     28 Complex operator+(Complex com1,int x)        //左操作数类型为复数,右操作数的类型为整数
     29 {
     30     return Complex(com1.real+x,com1.imag);
     31 }
     32 
     33 Complex operator+(int x,Complex com1)           //左操作数类型为整数,右操作数的类型为复数
     34 {
     35     return Complex(x+com1.real,com1.imag);
     36 }
     37 
     38 void Complex::showSum()
     39 {
     40     cout<<real;
     41     if(imag>0)
     42         cout<<"+";
     43     if(imag!=0)
     44         cout<<imag<<"i"<<endl;
     45 }
     46 
     47 class Point//坐标类
     48 {
     49 private:
     50     int x;
     51     int y;
     52 
     53 public:
     54     Point(int x,int y)
     55     {
     56         this->x=x;
     57         this->y=y;
     58     }
     59     friend void  operator++(Point & point);    //友元函数重载单目运算符++
     60     Point operator++();    //成员函数重载双目运算符++
     61     void showPoint();
     62 };
     63 
     64 void operator++(Point& point)//友元运算符重载函数
     65 {
     66     ++point.x;
     67     ++point.y;
     68 }
     69 
     70 Point Point::operator++()
     71 {
     72     ++x;
     73     ++y;
     74     return   *this;//返回当前对象
     75 }
     76 
     77 void Point::showPoint()
     78 {
     79     cout<<"("<<x<<","<<y<<")"<<endl;
     80 }
     81 
     82 int main()
     83 {
     84     //两个复数相加
     85     cout<<"两个复数相加:"<<std::endl;
     86 
     87     Complex com1(10,10),com2(20,-20),sum;
     88     sum=com1+com2;//或sum=com1.operator+(com2)
     89     cout<<"(10+10i)+(20-20i)=";
     90     sum.showSum();//输出复数相加结果
     91 
     92     //三个复数相加
     93     cout<<"三个复数相加:"<<endl;
     94 
     95     sum=com1+com2+com2;
     96     cout<<"(10+10i)+(20-20i)+(20-20i)=";
     97     sum.showSum();
     98 
     99     //整数和复数相加
    100     cout<<"整数和复数相加:"<<endl;
    101       
    102     Complex com3(5,10),total;
    103     total=com3+5;//或total=operator+(com1,5);
    104     cout<<"(5+10i)+5=";
    105     total.showSum();
    106 
    107     total=5+com3;//或total=operator+(5,com1);
    108     //只能用友元函数来重载运算符
    109     cout<<"5+(5+10i)=";
    110     total.showSum();
    111     
    112     //单目运算符++重载
    113     cout<<"单目运算符++重载:"<<std::endl;
    114 
    115     //注意:下述实现部分不能只用一个++point会造成二义性
    116     Point point(10,10);
    117     //调用友元函数
    118     operator++(point);//或++point
    119     cout<<"调用友元函数:++(10,10)=";
    120     point.showPoint();//输出坐标值
    121     
    122     //调用成员函数
    123     point=point.operator++();//或++point;
    124     cout<<"调用成员函数:++(10,10)=";
    125     point.showPoint();
    126 
    127     return    0;
    128 }
    129 /*
    130 两个复数相加:
    131 (10+10i)+(20-20i)=30-10i
    132 三个复数相加:
    133 (10+10i)+(20-20i)+(20-20i)=50-30i
    134 整数和复数相加:
    135 (5+10i)+5=10+10i
    136 5+(5+10i)=10+10i
    137 单目运算符++重载:
    138 调用友元函数:++(10,10)=(11,11)
    139 调用成员函数:++(10,10)=(12,12)
    140 */6】以下特例函数调用细节如何?
    
    关于调用细节。示例代码如下:
    
    
     1 #include<iostream>
     2 using namespace std;
     3 class B
     4 {
     5 public:
     6     B()
     7     {
     8         cout<<"Default  Construct"<<"  "<<this<<endl;
     9     }
    10     B(int i):data(i)
    11     {
    12         cout<<"Construct  By  :"<<this<<"  "<<data<<endl;
    13     }
    14     B(const B &b)
    15     {
    16         cout<<"Copy  Construct"<<"  "<<this<<"   "<<&b<<endl;
    17         data=b.data;
    18     }
    19      
    20     B &operator=(const B &obj)
    21     {
    22         cout<<"operator= "<<"   "<<this<<"   "<<&obj<<endl;
    23         if(this!=&obj)
    24         {
    25             data=obj.data;
    26         }
    27         return  *this;
    28     }
    29  
    30     ~B()
    31     {
    32         cout<<"Destructed"<<"   "<<this<<"  "<<data<<endl;
    33     }
    34     private:
    35         int data;
    36 };
    37 
    38 B &Func(B b)
    39 {
    40     B t(8);
    41     return t;
    42 }
    43 
    44 void main()
    45 {
    46     B t1(1);    
    47 
    48     B t2(5);  
    49     
    50     B t3=t1;  
    51     
    52     B t4(t3); 
    53     
    54     B  t5;    
    55     
    56     t5 = t2;    
    57     
    58     B t6 = Func(t2);
    59     
    60     B t7; 
    61     
    62     t7=Func(t2);
    63     
    64 }
    65 
    66 //运行结果如下:
    67 /*
    68 Construct  By  :0042FD74  1
    69 Construct  By  :0042FD68  5
    70 Copy  Construct  0042FD5C   0042FD74
    71 Copy  Construct  0042FD50   0042FD5C
    72 Default  Construct  0042FD44
    73 operator=    0042FD44   0042FD68
    74 Copy  Construct  0042FC34   0042FD68
    75 Construct  By  :0042FC18  8
    76 Destructed   0042FC18  8
    77 Destructed   0042FC34  5
    78 Copy  Construct  0042FD38   0042FC18
    79 Default  Construct  0042FD2C
    80 Copy  Construct  0042FC34   0042FD68
    81 Construct  By  :0042FC18  8
    82 Destructed   0042FC18  8
    83 Destructed   0042FC34  5
    84 operator=    0042FD2C   0042FC18
    85 Destructed   0042FD2C  -858993460
    86 Destructed   0042FD38  -858993460
    87 Destructed   0042FD44  5
    88 Destructed   0042FD50  1
    89 Destructed   0042FD5C  1
    90 Destructed   0042FD68  5
    91 Destructed   0042FD74  1
    92 */
    
    如有需要,希望仔细再研究,我到此而已。
    转载自:http://www.cnblogs.com/Braveliu/archive/2013/01/01/2841601.html
  • 相关阅读:
    构造方法中使用this的含义
    Android Bundle类
    Android中使用PULL方式解析XML文件
    Android 创建与解析XML(四)—— Pull方式
    File的getPath()和getAbsolutePath()和getCanonicalPath()的区别
    Android-取出SDcard卡下指定后缀名的文件
    page、request、session和application有什么区别?
    prepareStatement的用法和解释
    pageContext对象的用法
    使用JSP连接MySql数据库读取HTML表单数据进行存贮
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/4495770.html
Copyright © 2020-2023  润新知