C++面向对象高级编程(侯捷) 学习笔记

460 阅读3分钟

C++面向对象高级编程(侯捷) 学习笔记。

这是侯捷老师的所有C++技术课程中最基础最根本的一门课。 基础最是重要,勿在浮沙筑高台,着重的是大器与大气

视频连接

pdf连接、code连接

编写.h文件标准式的布局

image.png

类的构造函数

image.png

通过把构造函数,放在private区域,实现设计模式中的单例

image.png

参数的传递,尽量 by reference, 返回值 尽量 by reference

image.png

  • 返回值不能传引用的例子
inline complex&
__doapl(complex* ths, const complex& r)
{
    complex new_c;
    new_c.re = ths->re + r.re;
    new_c.im = ths->re + r.im;
    return new_c;
}

因为这里的new_c是在函数内部申请的内存,在函数结束时,内存被回收。所以不能用传递引用的形式返回值。

正确的写如下:

inline complex
__doapl(complex* ths, const complex& r)
{
    complex new_c;
    new_c.re = ths->re + r.re;
    new_c.im = ths->re + r.im;
    return new_c;
}

friend 友元

  • 自由取得friend的private成员
  • 相同class的各个objects互为friends

image.png

image.png

操作符重载 operator overloading

成员函数是作用在左边身上,所以c2 += c1执行时,下图中标红的this指向的是 c2

image.png

  • 对于 <<,执行是从左到右

image.png

拷贝构造函数

image.png

拷贝赋值函数

image.png

static local objects的生命周期

image.png

类的复合(Composition),表示has-a

图中例子,黄色部分,表示这是一个复合,即class queue has-a class dequeue.

同时,他也示范了一种设计模式:Adapter。即用现有的一个类,通过复合,暴露客户所需的接口和功能。 image.png

委托(Delegation)。通过引用的方式进行复合

注意:在复合的UML图中,菱形是实心的,而委托的UML图中,菱形是空心的。

额外的,下面的例子中,展示了字符串共享的思想:不同的三个String对象a、b、c,他们的rep字段共同指向同一个对象。用count实现引用计数。

image.png

继承与虚函数的关系

image.png

基于对象编程的例子

  • complex.h
#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__

  • complex_test.cpp
#include <iostream>
#include "complex.h"

using namespace std;

ostream&
operator << (ostream& os, const complex& x)
{
  return os << '(' << real (x) << ',' << imag (x) << ')';
}

int main()
{
  complex c1(2, 1);
  complex c2(4, 0);

  cout << c1 << endl;
  cout << c2 << endl;
  
  cout << c1+c2 << endl;
  cout << c1-c2 << endl;
  cout << c1*c2 << endl;
  cout << c1 / 2 << endl;
  
  cout << conj(c1) << endl;
  cout << norm(c1) << endl;
  cout << polar(10,4) << endl;
  
  cout << (c1 += c2) << endl;
  
  cout << (c1 == c2) << endl;
  cout << (c1 != c2) << endl;
  cout << +c2 << endl;
  cout << -c2 << endl;
  
  cout << (c2 - 2) << endl;
  cout << (5 + c2) << endl;
   
  return 0;
}

面向对象编程的例子

  • string.h
#ifndef __MYSTRING__
#define __MYSTRING__

class String
{
public:                                 
   String(const char* cstr=0);                     
   String(const String& str);                    
   String& operator=(const String& str);         
   ~String();                                    
   char* get_c_str() const { return m_data; }
private:
   char* m_data;
};

#include <cstring>

inline
String::String(const char* cstr)
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   
      m_data = new char[1];
      *m_data = '\0';
   }
}

inline
String::~String()
{
   delete[] m_data;
}

inline
String& String::operator=(const String& str)
{
   if (this == &str)
      return *this;

   delete[] m_data;
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
   return *this;
}

inline
String::String(const String& str)
{
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
}

#include <iostream>
using namespace std;

ostream& operator<<(ostream& os, const String& str)
{
   os << str.get_c_str();
   return os;
}

#endif
  • string_test.cpp
#include "string.h"
#include <iostream>

using namespace std;

int main()
{
  String s1("hello"); 
  String s2("world");
    
  String s3(s2);
  cout << s3 << endl;
  
  s3 = s1;
  cout << s3 << endl;     
  cout << s2 << endl;  
  cout << s1 << endl;      
}

委托、继承的例子。以设计模式Prototype为例

  • prototype.h
#include <iostream>
using namespace std;

#ifndef __MYPROTOTYPE__
#define __MYPROTOTYPE__

enum imageType
{
    LSAT, SPOT
};

class Image
{
public:
    virtual void draw() = 0;
    static Image *findAndClone(imageType);

protected:
    virtual imageType returnType() = 0;
    virtual Image *clone() = 0;
    // 添加类型
    static void addPrototype(Image *image)
    {
        _prototypes[_nextSlot++] = image;
    }

private:
    static Image *_prototypes[10];
    static int _nextSlot;
};

// 类的静态成员变量,一定要定义。即下面两行为Image的两个成员变量申请了空间
Image *Image::_prototypes[];
int Image::_nextSlot;

Image *Image::findAndClone(imageType type)
{
    for (int i = 0; i < _nextSlot; i++)
    {
        if (_prototypes[i]->returnType() == type)
        {
            return _prototypes[i]->clone();
        }
    }
}

class LandSatImage: public Image
{
public:
    imageType returnType()
    {
        return LSAT;
    }

    void draw()
    {
        cout << "LandSatImage::draw" << _id << endl;
    }

    Image *clone() 
    {
        return new LandSatImage(1); // 这里不能是 new LandSatImage(),因为默认的构造函数,实现是注册原型
    }

protected:
    LandSatImage(int dummy)
    {
        _id = _count++;
    }

private:
    /*
    定义一个静态成员,触发默认的构造函数,默认的构造函数实现,注册原型。
    */
    static LandSatImage _landSatImage; 
    LandSatImage()
    {
        addPrototype(this);
    }

    int _id;
    static int _count;

};
/*这行代码会创建一个对象,触发默认构造函数的调用,从而将原型添加到数组中
*/
LandSatImage LandSatImage::_landSatImage;
int LandSatImage::_count=1;


class SpotImage: public Image
{
public:
    imageType returnType()
    {
        return SPOT;
    }

    void draw()
    {
        cout << "SpotImage::draw" << endl;
    }

    Image *clone()
    {
        return new SpotImage(1);
    }

protected:
    SpotImage(int dummy)
    {
        _id = _count++;
    }

private:
    SpotImage()
    {
        addPrototype(this);
    }
    static SpotImage _spotImage;
    int _id;
    static int _count;
};

SpotImage SpotImage::_spotImage;
int SpotImage::_count = 1;




#endif   //__MYPROTOTYPE__
  • prototype_test.cpp
#include "prototype.h"

const int NUM_IMAGES = 8;
imageType input[NUM_IMAGES] =
{
    LSAT, LSAT, LSAT, SPOT, LSAT, SPOT, SPOT, LSAT
};

int main()
{
    Image *images[NUM_IMAGES];
    for (int i = 0; i < NUM_IMAGES; i++)
    {
        images[i] = Image::findAndClone(input[i]);
    }
    for (int i = 0; i < NUM_IMAGES; i++)
    {
        images[i]->draw();
    }
    for (int i = 0; i < NUM_IMAGES; i++)
    {
        delete images[i];
    }
    return 0;
}