C++面向对象高级编程(侯捷) 学习笔记。
这是侯捷老师的所有C++技术课程中最基础最根本的一门课。 基础最是重要,勿在浮沙筑高台,着重的是大器与大气
编写.h文件标准式的布局
类的构造函数
通过把构造函数,放在private区域,实现设计模式中的单例
参数的传递,尽量 by reference, 返回值 尽量 by reference
- 返回值不能传引用的例子
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
操作符重载 operator overloading
成员函数是作用在左边身上,所以c2 += c1执行时,下图中标红的this指向的是 c2。
- 对于
<<,执行是从左到右
拷贝构造函数
拷贝赋值函数
static local objects的生命周期
类的复合(Composition),表示has-a
图中例子,黄色部分,表示这是一个复合,即class queue has-a class dequeue.
同时,他也示范了一种设计模式:Adapter。即用现有的一个类,通过复合,暴露客户所需的接口和功能。
委托(Delegation)。通过引用的方式进行复合
注意:在复合的UML图中,菱形是实心的,而委托的UML图中,菱形是空心的。
额外的,下面的例子中,展示了字符串共享的思想:不同的三个String对象a、b、c,他们的rep字段共同指向同一个对象。用count实现引用计数。
继承与虚函数的关系
基于对象编程的例子
- 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;
}