C++再修(一)————通过一个头文件,来讲解整个程序的部分概念

这个是候捷版本的C++面向对象高级开发的课程,感觉不错,记下来

头文件的写法:(防卫式的声明)

头文件有一种非常正规的写法,一定要学习起来:

#ifndef _COMPLEX_
#define _COMPLEX_
          .
          .
          .
          .
          .
#endif

一个头文件先这么写(如上),为什么要写这个东西呢?因为有很多程序,要用到你这个头文件,或者你自己也可能用到,如果有很多头文件,用户在调用(include)的时候,会出现到底先调用那个头文件的问题,头文件很多的话,会很难排,所以,这种防卫式的声明,非常管用。大致原理是:但机器执行的时候,一读到第一行代码告诉编译器说:一进来,如果不曾经定义过“_COMPLEX_”这个东西,那么就把它定义出来,然后就继续执行下面的内容,所以,当程序第一此调用(include)这个头文件的话,很容易就被定义好了,在同一个函数里面,第二次再(include)的时候,因为“_COMPLEX_”已经被定义好了,就不会再进来了,下面的代码也就不会再被执行了,这样就可以避免头文件被重复引入。

 

Header(头文件)的布局:

那么下面就开始写中间的内容部分,先写第一部分:

class的声明(declaration):

任何一个class一定有一个“头”(class head),这里面你就需要去设计,我的复数应该具备什么样的数据,我的应该准备什么样的函数,才能够满足使用复数的人的需求,比如说,大家都知道数学里面有个共轭复数,那我就应该在这里写一个共轭复数这样的函数出来。那结果就是这样

 

class complex  /*............................<-class head,“complex”也是类的名称*/

/*................................class body如下*/
{ 
public:
    complex  (double r = 0, double i = 0)
       :    re  (r),  im  (i)
   {  }
    complex&  opeartor  +=  {const complex&};
    double  real () const { return re;}
    double  imag () const { return im;} 
private:
   double re, im;/*复数里面有实部和虚部,那我就人为的来定义一下*/ 

   friend complex& __doapl (complex*, const complex&)
}; 

 

 在函数当中的用法为:

{
    complex  c1(2,1);
    complex  c2;
    . . .
}

 

inline函数:最好将大部分函数都写成inline的形式,上例中“{ return re; }”“{ return im;}”构成了inline函数,函数若在class body内定义完成,便自动成为inline函数,如果在外头定义,就不是inline函数了。但是,要注意的是,如果函数太过于复杂,就没有办法inline了。比如说,就这两个函数,我们设计成inline函数,但具体是不是按inline来编译,那就是编译器的事情了。

如果是在非class body下定义完成的inline函数,举例如下:

inline double
imag(const complex&  x)
{
    return  x.imag  () ;
}

 

在一个class body中,很明显可以区分为几大段,用什么来区分呢?就是“public”(公开的,被外界所看的到的)和“private”(只有我class里面才可以看得到)。那什么东西才可以放到“private”里面呢?当然是数据的部分,因为我们需要的数据是封装起来的,不要被外界任意看到。那函数部分呢?函数也分两种,一种给外界用的,一种来处理自己私人的事情,在这个例子里面,大部分函数都是要被外界所使用的,所以,所有函数我们都放在"public"里面。这些段落是可以交错的,想到一段写“public”,再想到一段写“private”无先后顺序,或只能写两段。

那这有什么影响呢?

举个例子:

{
    complex  c1(2,1);
    cout  <<  c1.re;
    cout  <<  c1.im;
}

这样写就是错的,因为“re”和“im”定义在“private”里面,是不会被读取出来的。

而这样写:

{
    complex  c1{2,1};
    cout  <<  c1.real();
    cout  <<  c1.imag();
}

是可以的,因为调用的是"public"里面的“real”和“imag”函数。

最后总结一下,我们把“public”“private”他们所形成的这个区域,称为:“access level ”访问级别。

如果你写的函数打算被外界调用,那你就放在“public”里面,如果你写的函数,只打算在内部被运用,没打算被外界调用,那你就放在“private”

 

在C++里面,如果你想创建一个东西(就是对象),有一个函数会自动被调用起来,不需要人工调用,自动起来。这就叫做构造函数,比如,下面这个例子:

{
    complex c1(2,1);
    complex c2;
    complex * p = new complex(4);
    . . .
}

这三个都在创建对象,创建对象的话,一定有一个函数在里面。

       这种构造函数的写法很独特,它的函数名称,一定要跟类的函数名称相同,才能够叫做构造函数,并且,它可以用有参数,在class body 里面,complex头文件定义部分。自然想到实部和虚部两个部分来定义。

  complex  (double r = 0, double i = 0)
       :    re  (r),  im  (i)/*这行是初始化,只有构造函数才有,表示把r分给re,把i分给im*/
   {  }

其中“r=0”和“i=0”都是默认实参(default argument)。就像上面的那个c1有指明参数,那就是用它指明的,c2没有指明的参数,那就用class body 里面定义好的默认实参好了

 充分利用每个函数的特点,是判断编写是否大气的标志,上面就是大气的一个典范!

 构造函数可以有很多个-overloading(重载),比如说你设计一个类,等待外界来创建一个对象,创建对象的时候要怎么创建?假设你有三种设计思路,那你就写出三个构造函数,C里面是不允许这样做的,但C++是允许的。相同函数名称,却不止一个,这个就叫做overloading

举个例子:

void real(double r)   ( re=r;)

这样定义也是可以的,虽然,会跟class body 里面的real冲突,它们机器码不一样。

但如果是这种情况下:

complex  (double r = 0, double i = 0)
       :    re  (r),  im  (i)
   {  }
complex   ()    :   re(0) , im(0)  {}

因为重名,会出现冲突。

函数重载,一般多发生在构造函数里面。

 

* class template(模板)

在上面的class中,实部和虚部是人工定义为double值,那我如果要设计另外一个复数,它里面的类型是浮点数(float),或者是整数,怎么办?可上面已经写死了,不能动了,那就只好再把原来的程序原样敲一遍,只到定义实部和虚部的部分,改一下,这样写太麻烦了,于是,C++的设计者,就发明了针对类似这种情况的东西————class template(模板),写成:把实部和虚部的位置不要先写死,我想要以后用的时候,我再指定 

template<typename T>/*提前告诉编译器,T是一个type*/
class complex
{ 
public:
    complex  (double r = 0, double i = 0)
       :    re  (r),  im  (i)
   {  }
    complex&  opeartor  +=  {const complex&};
    double  real    ()   const  {  retrun  re;  }
    double  imag   ()   const  { return  im;}
private:
    T  re,  im;/*T的意思可以理解成告诉编译器:我现在是什么类型,我还没有决定呦!*/

    friend  complex& __doapl  (complex*,  const  complex&)
};

在函数当中的用法为:

{
    complex<double>  c1(2.5,1.5);
    complex<int>  c2(2, 6);
    . . .
}

 

posted @ 2017-09-25 09:08  恋.蛩音  阅读(324)  评论(0编辑  收藏  举报