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

一 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

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
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 c1(2.5,1.5);
      complex 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<

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<

若是+重载函数为全局函数,就没法考虑实数+复数和复数+实数的情况,而只能考虑复数加实数的情况。
临时对象 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 

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++笔记一(面向对象编程上))