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<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__
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容