美文网首页我爱编程
C++笔记一(面向对象编程上)

C++笔记一(面向对象编程上)

作者: 小小出大炮 | 来源:发表于2017-04-18 21:29 被阅读0次

    一 C++编程简介:

    1.1 C++历史

    (1)C++出现在1983年,当时被叫做C with Class。
    (2)历史版本:C++98(1.0)、C++03(TR1,Technical Report 1)、C++11(2.0)、C++14、C++17(2017年刚出)。
    (3)C++由C++语言和C++标准库组成。

    1.2 C++的class经典分类

    (1)C++without pointer members(课程示例Complex)。
    (2)C++with pointer members(课程示例String)。

    1.3 Object Based 和Object Oriented

    (1)Object Based(基于对象)面对的是单一class的设计;
    (2)Object Oriented(面向对象,对象导向)面对的是多重class的设计,classes和classes之间的关系。

    二 头文件与类的声明

    2.1 C++与C的区别

    C与C++关于数据与函数的区别:
    (1)C有数据和函数,根据数据类型创建具体的数据,函数来处理这些数据,弊端是这些数据是全局的,之后可能会出错;
    (2)C++是把数据和处理这些数据的函数封装在一起,叫做class或者struct,C++中class和struct仅有微小区别。

    2.2 class经典分类的数据区与函数

    (1)C++不带指针的类complex数据区是复数的实部及虚部,成员函数为加、减、乘、除、共轭、正弦等;
    (2)C++带指针的类string数据区是字符,其实就是一个指针,指向一串字符,成员函数为拷贝、输出、附加、插入等。

    2.3 C++基本代码形式

    (1)C++的基本代码形式:类声明(.h)+main函数+类定义(.cpp)+标准库(.h)
    (2)C++延伸文件名不一定是.h或者.cpp,也可能是.hpp或者其它甚至无延伸名。
    (3)C与C++关于输出的头文件的区别是,C的头文件是stdio.h,C++的头文件是iostream。

    2.4 头文件防卫式声明

    #ifndef  _COMPLEX_
    #define  _COMPLEX_
    、、、
    #endif
    

    头文件中要写防卫式声明,这样的作用是:防止由于同一个头文件被包含多次,而导致了重复定义。

    2.5 头文件布局

    #ifndef  _COMPLEX_
    #define  _COMPLEX_
    
    #include<cmath>
    
    class ostream;        //前置声明
    class complex;
    complex&
     _doapl(complex* ths,const complex &r);
    
    class complex         //类声明
    {
    ...
    };
    
    complex::function...  //类定义
    #endif
    

    (1)头文件布局除了防卫式声明、包含头文件以外,还包含三个主要部分:前置声明、类的声明、类的定义。
    (2)类的声明包含类的头(head)和类的主体(body),有的函数在类的body里面定义,有的在类的body外面定义。

    2.6 类模板初体验

    template<typename T>
    class complex
    {
    public:
          complex(T r = 0,T i = 0)
          : re ( r ) , im ( i )
          {}
          complex& operator +=(const complex&);
          T real() const { return re;}
          T imag() const { return im;}
    private:
          T re,im;
          friend complex& _doapl (complex*,const complex&);
    };
    void main()
    {
          complex<double> c1(2.5,1.5);
          complex<int> c2(2,6);
          ...
    }
    

    为了不限制类的成员变量的类型,采用模板的形式定义成员变量,等以后需要的用的时候再定义数据类型。

    三 构造函数

    3.1 inline(内联)函数

    class complex
    {
    public:
           complex(double r = 0,double i = 0)
           :re (r) ,im ( i )
           { }
           complex& operator +=(const complex&);
           double real() const { return re;}      //自动成为inline候选人
           double imag() const { return im;}
    private:
           double re,im;
           friend complex& _doapl (complex*,const complex&);
    };
    inline double
    imag(const complex& x)
    {
           return x.imag();
    }
    

    如果函数在class本体内定义,则它自动变成内联(inline)函数候选人 ,内联函数的效率比较高。若函数较为复杂(例如函数内有循环、递归等)或代码较长,则编译器无法将它变为内联函数。

    3.2 类的访问级别

    在类的本体内有三种访问级别:public、protect、private。
    (1)private:只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类的对象也不能访问。
    (2)protected:可以被该类中的函数、子类的函数、以及其友元函数访问,但不能被该类的对象访问。
    (3)public:可以被该类中的函数、子类的函数、其友元函数访问,也可以由该类的对象访问。

    3.3 构造函数

    class complex
    {
    public:
           complex(double r = 0,double i = 0)  //构造函数与类名称一致,默认实参
           :re (r) ,im ( i )                   //初始化列表
           { }
           complex& operator +=(const complex&);
    ...
    }
    

    构造函数:创建对象时自动被调用的函数。
    (1)和类的名称相同,可以有默认参数,不需要返回类型。
    (2)比较好的方法是利用构造函数进行初始化列表,初始化列表在编译前执行,比在构造函数大括号里面赋初值效率高,赋初值在编译后执行。
    (3)构造函数可以有很多个,叫做函数的重载。

    四 参数传递与返回值

    4.1 singleton设计模式

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

    构造函数被放在private区表示这个类不能在外界创建对象。
    设计模式Singleton:外界只能通过调用getInstance函数才能得到A的对象,不能直接创建A的对象。

    4.2 const初体验

    class complex
    {
    ...
         double real() const {return re;)
         double imag() const {return im;)
    ...
    }
    void main()
    {
         const complex c1(2,1);
         cout<<c1.real():
         cout<<c1.imag();
    }
    

    const修饰函数表示外界调用该函数时不会改变里面的数据。使用者创建对象时加const,但是类里面的函数没有用const,会出错!

    4.3 参数传递与返回值

    (1)参数传递传引用比传值有效率,传引用和传指针一样快(四个字节),但形式比指针漂亮。传引用又不想这个函 数改变传进去的东西,可以在前面用const修饰。
    (2)返回值传递尽量传引用,在允许的情况下。返回本地变量,不可以传引用。

    4.4 友元函数

    class complex
    {public:
           complex(double r = 0,double i = 0)
           :re (r) ,im ( i )
           { }
           int func(const complex& param)
           {return param.re+param.im;}
    private:
           double re,im;
    };
    void main()
    {
           complex c1(2,1)
           complex c2;
           c2.func(c1);
    }
    

    (1)友元函数可以自由取得friend的private成员,友元打破了c++的封装性。
    (2)相同class的各个objects互为友元。

    五 操作符重载和临时对象

    5.1 this指针

    通常在class定义时要用到类型变量自身时,因为这时候还不知道变量名(为了通用也不可能固定实际的变量名), 就用this这样的指针来使用变量自身。
    引用链接:http://blog.csdn.net/feiyond/article/details/1652505

    5.2 操作符重载——成员函数

    inline complex& 
    _doapl(complex* ths, const complex& r) //do assignment plus 
    {
         ths->re += r.re;
         ths->im += r.im;
         return *ths;
    }
    
    inline complex& 
    complex::operator += (const complex& r)
    {
         return _doapl (this,r) ;
    }
    //编译器是如何看待的如下
    /*inline complex&      
    complex::operator += (this, const complex& r)
    {
        return _doapl (this,r) ;
    }*/
    void main()
    {
        complex c1(2,1);
        complex c2(5);
    
        c2 += c1 ;
    }
    

    (1)所有的成员函数函数都带有一个隐藏的参数——this指针。
    (2)重载+=运算符,返回值是complex&而不是void,如对于:c2 += c1 不需要知道返回值,但是如果对于:c3 += c2 += c1,返回值void就会出错了。

    5.3 操作符重载——非成员函数

    inline complex
    operator + (const complex& x,const complex& y)
    {
          return complex (real (x)+real (y),imag (x)+imag (y));
    }
    inline complex
    operator + (const complex& x,const complex& y)
    {
          return complex (real (x)+ y ,imag (x));
    }
    inline complex
    operator + (const complex& x,const complex& y)
    {
          return complex ( x +real (y),imag (y));
    }
    void main()
    {
          complex c1(2,1);
          complex c2;
          complex();
          complex(4,5);
          c2 = c1 + c2;  //两个复数相加
          c2 = c1 + 5;   //复数加实数
          c2 = 7 + c1;   //实数加复数
          cout<<complex(2);
    }
    

    若是+重载函数为全局函数,就没法考虑实数+复数和复数+实数的情况,而只能考虑复数加实数的情况。
    临时对象 typename():表示创建一个临时对象,作用时间到下一行结束。这些临时对象绝不可return by reference。因为它们是local object。

    5.4 小结

    (1)构造函数尽量用初始化列表;
    (2)函数该不该加const一定要考虑;
    (3)参数的传递尽量用引用,要不要加const要考虑;
    (4)返回值尽量要用引用,在可以的情况下;
    (5)数据尽量放在private,函数尽量放在public;

    六 Complex类完整代码:

    #ifndef __MYCOMPLEX__
    #define __MYCOMPLEX__
    
    class complex; 
    complex&
      __doapl (complex* ths, const complex& r);
    complex&
      __doami (complex* ths, const complex& r);
    complex&
      __doaml (complex* ths, const complex& r);
    
    
    class complex
    {
    public:
      complex (double r = 0, double i = 0): re (r), im (i) { }
      complex& operator += (const complex&);
      complex& operator -= (const complex&);
      complex& operator *= (const complex&);
      complex& operator /= (const complex&);
      double real () const { return re; }
      double imag () const { return im; }
    private:
      double re, im;
    
      friend complex& __doapl (complex *, const complex&);
      friend complex& __doami (complex *, const complex&);
      friend complex& __doaml (complex *, const complex&);
    };
    
    
    inline complex&
    __doapl (complex* ths, const complex& r)
    {
      ths->re += r.re;
      ths->im += r.im;
      return *ths;
    }
     
    inline complex&
    complex::operator += (const complex& r)
    {
      return __doapl (this, r);
    }
    
    inline complex&
    __doami (complex* ths, const complex& r)
    {
      ths->re -= r.re;
      ths->im -= r.im;
      return *ths;
    }
     
    inline complex&
    complex::operator -= (const complex& r)
    {
      return __doami (this, r);
    }
     
    inline complex&
    __doaml (complex* ths, const complex& r)
    {
      double f = ths->re * r.re - ths->im * r.im;
      ths->im = ths->re * r.im + ths->im * r.re;
      ths->re = f;
      return *ths;
    }
    
    inline complex&
    complex::operator *= (const complex& r)
    {
      return __doaml (this, r);
    }
     
    inline double
    imag (const complex& x)
    {
      return x.imag ();
    }
    
    inline double
    real (const complex& x)
    {
      return x.real ();
    }
    
    inline complex
    operator + (const complex& x, const complex& y)
    {
      return complex (real (x) + real (y), imag (x) + imag (y));
    }
    
    inline complex
    operator + (const complex& x, double y)
    {
      return complex (real (x) + y, imag (x));
    }
    
    inline complex
    operator + (double x, const complex& y)
    {
      return complex (x + real (y), imag (y));
    }
    
    inline complex
    operator - (const complex& x, const complex& y)
    {
      return complex (real (x) - real (y), imag (x) - imag (y));
    }
    
    inline complex
    operator - (const complex& x, double y)
    {
      return complex (real (x) - y, imag (x));
    }
    
    inline complex
    operator - (double x, const complex& y)
    {
      return complex (x - real (y), - imag (y));
    }
    
    inline complex
    operator * (const complex& x, const complex& y)
    {
      return complex (real (x) * real (y) - imag (x) * imag (y),
                   real (x) * imag (y) + imag (x) * real (y));
    }
    
    inline complex
    operator * (const complex& x, double y)
    {
      return complex (real (x) * y, imag (x) * y);
    }
    
    inline complex
    operator * (double x, const complex& y)
    {
      return complex (x * real (y), x * imag (y));
    }
    
    complex
    operator / (const complex& x, double y)
    {
      return complex (real (x) / y, imag (x) / y);
    }
    
    inline complex
    operator + (const complex& x)
    {
      return x;
    }
    
    inline complex
    operator - (const complex& x)
    {
      return complex (-real (x), -imag (x));
    }
    
    inline bool
    operator == (const complex& x, const complex& y)
    {
      return real (x) == real (y) && imag (x) == imag (y);
    }
    
    inline bool
    operator == (const complex& x, double y)
    {
      return real (x) == y && imag (x) == 0;
    }
    
    inline bool
    operator == (double x, const complex& y)
    {
      return x == real (y) && imag (y) == 0;
    }
    
    inline bool
    operator != (const complex& x, const complex& y)
    {
      return real (x) != real (y) || imag (x) != imag (y);
    }
    
    inline bool
    operator != (const complex& x, double y)
    {
      return real (x) != y || imag (x) != 0;
    }
    
    inline bool
    operator != (double x, const complex& y)
    {
      return x != real (y) || imag (y) != 0;
    }
    
    #include <cmath>
    
    inline complex
    polar (double r, double t)
    {
      return complex (r * cos (t), r * sin (t));
    }
    
    inline complex
    conj (const complex& x) 
    {
      return complex (real (x), -imag (x));
    }
    
    inline double
    norm (const complex& x)
    {
      return real (x) * real (x) + imag (x) * imag (x);
    }
    
    #endif   //__MYCOMPLEX__
    

    相关文章

      网友评论

        本文标题:C++笔记一(面向对象编程上)

        本文链接:https://www.haomeiwen.com/subject/nomtzttx.html