• C++ class without pointer members


    •   写在前面

     

    • Object Oriented

    class 的分类:带指针的class和不带指针的class,

    class 的声明

           

    这里有一个inline的概念,写在类里面的默认为inline,写在class外部的只有声明,为inline才有可能编译成Inline,最终编译时是否为inline,由编译器决定。Inline函数速度快.

    public:

    private:所有数据都应放在private,函数根据是否想要被外界调

    使用对象

      ×   √ 

    • 构造函数:

    想要创建一个对象,会自动调用的函数就是构造函数,如上,构造函数与类同名,没有返回类型,不需要有,因为构造函数就是要来创建对象的,此处对象就是complex,上面定义的构造函数使用了列表初始化,并且这种初始化只有构造函数才有,其它函数是没有的,并且给出了default argument

    这里多说一些,一个数值的设定有两个阶段,一个是初始化,一个是后面再赋值(assign),所以列表初始化和在函数体赋值是不同的。

    与构造函数对应是析构函数,但是这个例子中不需要写析构函数,前面提到过class的经典分类,不带指针的class多半需用写析构函数

    构造函数可以有多个-overloading,但是存在歧义的不可以,如下:

    complex() :re(0), im(0) {}//不可以,ambiguous

    如下面的对象c2,都没有给参数,编译器发现 可以调用上面的,但是编译器也发现class中的构造函数虽然有参数,但是有默认值,也可以调用,因此编译器就不知调用哪个了

    创建对象

           

    构造函数放在private中,即不允许外界调用构造函数

    class A {
    public:
        static A& getInstance();
    private:
        A();
        A(const A& rhs);
    
    };
    
    A& A::getInstance()
    {
        static A a;
        return a;
    }

    外界只能用一份A,即static的部分,外界用的时候不能使用传统的调用方式,只能通过getInstance()函数

    •  参数传递与返回值
    double real()const { return re; }
    double imag()const { return im; }

    看上面的代码,都是const型的,因为我不需要改变数据,只是将数据拿出来,看下面两种情况

              A.        B.

    如果我的函数没用定义为const类型,B中的调用就是错误的,使用者本想,我只是返回数据,并不改变,所以创建了一个常对象,但是由于函数没有定义为const,所以就会出现调用错误。

    •  参数传递:

    pass by value  vs pass by reference(to const)

    pass by value 就是整包都传过去,数据多大就传多大,传的数据是压到static栈中的,本例中,传的是double,是4个字节,传的就是4个字节,若传的数据很大呢,效率就低,所以尽量不要pass by value,  可以pass by reference ,reference在底部就是指针,

     1 ostream& operator <<(ostream& os, const complex& x)
     2 {
     3     return os << '(' << real(x) << ',' << imag(x) << ')';
     4 }
     5 int main()
     6 {
     7     complex c1(2, 1);
     8     complex c2;
     9     c2 += c1;
    10     cout << c2;
    11 }

    第7,8行会调用构造函数,通过pass by lalue的方式,第9行会调用1-4行的函数,pass by reference的方式。返回值的传递也尽量pass by reference

    friend complex& __doapl(complex*, const complex&);//return value :pass by reference

    后面会给出上面函数的detail

    下面看一种情况,为什么可以这样使用

    int func(const complex& param)
        {
            return param.re + param.im;
        }
    //用法
    complex c3;
    c3.func(c1);

    可以这样理解:相同class的各个objects 互为friends

     class body外的各种定义什么情况下可以pass by value,什么情况下可以pass by reference

    首先看看什么情况不能return by reference

     1 inline complex&
     2 __doapl(complex* ths, const complex& r)
     3 {
     4     ths->re += r.re;//第一参数将会被改动
     5     ths->im += r.im;//第二参数不会被改动
     6     return *ths;
     7 }
     8 inline complex&
     9 complex::operator+=(const complex& r)
    10 {
    11     return __doapl(this, r);
    12 }

     这里,函数将结果放在第一个参数中,有专门的存储的空间,还有一种情况就是函数专门开辟一个空间存放结果,如果只是

    return c1 + c2;

    这时,是一个临时开辟的local变量存储c1+c2的结果,函数结束,这个临时变量的生命就结束了,这时,就不能返回reference

    • 操作符重载(-1,成员函数) this

    想象我们在数学中的复数,有哪些操作,比如相加,复数+复数,复数+实数,复数+纯虚数,

    继续看上面代码,编译器看到c2+=c1,就会把操作符作用到左边c2身上,上面的inline complex& complex::operator+=(const complex& r){}相当于

    inline complex& complex::operator(this,const complex& r){}

    为什么可以这样呢,这就是上面辩题中写道的操作符重载之成员函数,因为所有成员函数带有一个隐藏的参数this,谁调用这个函数谁就是this,这里this是c2,

    Note:this不可以写在参数列表中,用可以像函数体中那样用,return __doapl(this,r);

    • return by reference 语法分析

    继续看上面的代码,看函数定义时的返回类型是complex&,函数体内返回的却是*ths,这样是正确的,因为,传递者无需知道接收者是以reference形式接收

    class body之外的函数定义

    operator overloading(操作符重载-2,非成员函数)无this

    考虑到用户的行为,定义了三种+ 形式

     1 inline complex
     2 operator +(const complex& x, const complex& y)
     3 {
     4     return  complex(real(x) + real(y), imag(x) + imag(y));
     5 }
     6 
     7 inline complex 
     8 operator +(const complex& x, double y)
     9 {
    10     return complex(real(x) + y, imag(y));
    11 }
    12 
    13 inline complex
    14 operator +(double x, const complex& y)
    15 {
    16     return complex(x + real(y), imag(y));
    17 }

    如上,对于上面的操作符重载,没有this pointer,因为是全域函数,不再是成员函数

    • temp object (临时对象)tempname()

    再看上面的代码,return by value,对于上面的代码,绝不可以return by reference,因为他们返回的一定是local object,因为加的结果是函数临时创建的,函数结束,临时变量死亡,

    解释一下:tempname(),此处是complex(),就是创建临时对象,tempname()类似于Int(),

    operator +(const complex& x)
    {
        return x;
    }
    
    inline complex
    operator -(const complex& x)
    {
        return complex(-real(x), -imag(x));
    }
    //使用
    {
        complex c1(2, 1);
        complex c2;
        cout << -c1;
        cout << +c1;
    }

    这里是return  by value,这里可是return by reference,因为,这里结果没有改变,也没有创建新的临时对象,所以是可以return by reference的。

    接下来还是操作符重载,考察的东西一样,语法上没有新的了,

    inline bool
    operator ==(const complex& x, const complex& y)
    {
        return real(x) == real(y) && imag(x) == iamg(y);
    }
    inline bool
    operator ==(const complex& x, double y)
    {
        return real(x) == y && iamg(x) == 0;
    }
    
    inline bool
    operator ==(double x, complex& y)
    {
        return x == real(y) && iamg(y) == 0;
    }
    
    inline bool
    operator !=(const complex& x, complex& y)
    {
        return real(x) != real(y) || imag(x) != imag(y);
    }
    
    inline bool
    operator !=(const complex& x, double y)
    {
        return real(x) != y || iamg(x) != 0;
    }
    
    inline bool 
    operator !=(double x, complex& y)
    {
        return x != real(y) || iamg(y) != 0;
    }
    
    inline complex
    conj(const complex& x)
    {
        return complex(real(x), -imag(y));
    }
    View Code
    ostream& operator <<(ostream& os, const complex& x)
    {
        return os << '(' << real(x) << ',' << imag(x) << ')';
    }
    
    //使用
    {
    cout << conj(c1);
    cout << c1 << conj(c1);
    }

    "<<"作用在左边,这里绝不能写成成员函数,必须写成全域函数。os也不可是const的,因为每往cout中放入“东西”的时候都是在改变os中的内容,若将返回类型 ostream& ,改为 void 可以吗?

    如果只是输出一个是可以的(上面第一处使用),如果连续输出是不可以的(第二处使用),

     下面是完整的代码(还有很多操作没写,但写的已经涵盖了这种类型的class的几乎所有语法,有时间再补全):

      1 #pragma once
      2 #ifndef __COMPLEX__
      3 #define __COMPLEX__
      4 
      5 class complex {
      6 public:
      7     complex(double r = 0, double i = 0) :re(r), im(i) {}//construct function
      8     //complex() :re(0), im(0) {}//不可以,ambiguous
      9     complex& operator +=(const complex&);//two choices,member func or non-member func,
     10     //here is member func,do not need to change the value,so is const
     11     double real()const { return re; }
     12     double imag()const { return im; }
     13     int func(const complex& param)
     14     {
     15         return param.re + param.im;
     16     }
     17 private:
     18     double re, im;
     19     friend complex& __doapl(complex*, const complex&);//return value :pass by reference
     20 
     21 };
     22 
     23 inline complex&
     24 __doapl(complex* ths, const complex& r)
     25 {
     26     ths->re += r.re;//第一参数将会被改动
     27     ths->im += r.im;//第二参数不会被改动
     28     return *ths;
     29     
     30 }
     31 inline complex&
     32 complex::operator+=(const complex& r)//the right is not change,so is const,the left
     33 {//has already existed,so return by reference
     34     return __doapl(this, r);
     35 }
     36 inline double
     37 real(const complex& x)
     38 {
     39     return x.real();
     40 }
     41 inline double
     42 imag(const complex& x)
     43 {
     44     return x.imag();
     45 }
     46 //"+"has more than one cases,so set it as the non-member func
     47 inline complex
     48 operator +(const complex& x, const complex& y)
     49 {//the sum result will be put in a local variable,so return by value
     50     return  complex(real(x) + real(y), imag(x) + imag(y));
     51 }
     52 
     53 inline complex 
     54 operator +(const complex& x, double y)
     55 {
     56     return complex(real(x) + y, imag(y));
     57 }
     58 
     59 inline complex
     60 operator +(double x, const complex& y)
     61 {
     62     return complex(x + real(y), imag(y));
     63 }
     64 inline complex
     65 operator +(const complex& x)
     66 {
     67     return x;
     68 }
     69 
     70 inline complex
     71 operator -(const complex& x)
     72 {
     73     return complex(-real(x), -imag(x));
     74 }
     75 
     76 inline bool
     77 operator ==(const complex& x, const complex& y)
     78 {
     79     return real(x) == real(y) && imag(x) == imag(y);
     80 }
     81 inline bool
     82 operator ==(const complex& x, double y)
     83 {
     84     return real(x) == y && imag(x) == 0;
     85 }
     86 
     87 inline bool
     88 operator ==(double x, complex& y)
     89 {
     90     return x == real(y) && iamg(y) == 0;
     91 }
     92 
     93 inline bool
     94 operator !=(const complex& x, complex& y)
     95 {
     96     return real(x) != real(y) || imag(x) != imag(y);
     97 }
     98 
     99 inline bool
    100 operator !=(const complex& x, double y)
    101 {
    102     return real(x) != y || imag(x) != 0;
    103 }
    104 
    105 inline bool 
    106 operator !=(double x, complex& y)
    107 {
    108     return x != real(y) || imag(y) != 0;
    109 }
    110 
    111 inline complex
    112 conj(const complex& x)
    113 {
    114     return complex(real(x), -imag(x));
    115 }
    116 
    117 #endif
    View Code

    测试代码有时间再补

  • 相关阅读:
    Ubuntu 18.04.3 更改系统语言为简体中文
    Centos7.3、nginx环境下部署hugo博客
    Centos7.3 卸载 Nginx(彻底卸载) 并重新安装 Nginx(RPM源yum安装)
    Centos7.3、nginx环境下部署hexo博客(非git推送方式)
    使用阿里云对象存储OSS+PicGo搭建图床
    Hexo博客添加LiveRe评论系统
    使用 jsDelivr CDN加速Github 仓库的图片
    解决win10一开机占用内存就飙到70%的问题
    [Andriod官方训练教程]管理Activity的生命活动之停止和重启一个Activity
    [Andriod官方训练教程]支持不同的设备之支持不同的语言
  • 原文地址:https://www.cnblogs.com/Holly-blog/p/8411091.html
Copyright © 2020-2023  润新知