p10. 类模板,函数模板,static
static
andthis
1
2
3
4
5
6
7
8
9
10
11
12
13class Account {
public:
static double m_rate;
static void set_rate (const double& x) { m_rate = x; }
};
double Account::m_rate = 8.0; //definition: 分配内存
int main () {
Account::set_rate(5.0);
Account a;
a.set_rate(7.0);
}- 成员函数有一个默认的参数
this*
, 不用写到参数里 - static数据是可以共享的(eg. 银行的利率),
static
成员函数没有this*
, 只能处理static
数据 - 调用
static
函数的方式:- 通过
object
来调用 –> 没有this*
- 通过
class name
来调用 –> 可能还没有创建对象
- 通过
- 成员函数有一个默认的参数
class template
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18template <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;
};
{
complex<double> c1(1.2, 1.5);
complex<int> c2(2, 3);
...
}function template
: 对于不同的class,可以用一个函数- 可以不指定类名,编译器会对
function template
进行参数推导(argument deduction)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21template <class T>
inline
const T& mini(const T& a, const T& b)
{
return b < a ? b : a;
}
class stone
{
public:
stone (int h, int we)
: _h(h), _weight(we)
{ }
bool operator < (cosnt stone& rhs) const
{
return _weight < rhs._weight;
}
private:
int _h, _weight;
};
stone r1(2, 3), r2(2, 3);
Stone r3 = mini(r1, r2);
- 可以不指定类名,编译器会对
namespace
- using directive –>
using namespace std;
- using declaration –>
using std::cout;
- using directive –>
p11. 组合与继承
组合 (
composition
) -> has-acontainer
空心菱形指向component
queue
<>—deque
- e.g. queue has deque, deque inside queue (queue的所有功能都是靠deque来实现) –> Adapter (减少功能)
1
2
3
4
5template <class T>
class queue {
protected:
deque<T> c;
}; - 组合下的构造和析构
Container(queue) --> Component(deque)
- 构造由内而外: 先调用
Component
的default构造函数, 再调用Container
- 析构由外而内: 先执行自己(
container
), 再调用Component
- 生命是一起出现 一起消失
委托 (
Delegation
) -> composition by reference- 实心菱形指向
component
- String <>—StringRep
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// file String.hpp
class StringRep;
class String {
public:
String();
String(const char* s);
String(const String& s);
String &operator=(const String& s);
~String();
}
private:
StringRep* rep; // pimpl: point to implementation
};
// file String.cpp
namespace {
class StringRep {
friend class String;
StringRep(const char* s);
~StringRep();
int count; // count the number of refernece
char* rep;
};
}- 编译防火墙,左边只需编译一次,只改变指向的那个类
- 生命不一定是同时出现的
- 多个指针指向同一个字符串,count用来记录reference的数目,读不影响,写入时需要单独复制一份给每个指针
- 实心菱形指向
继承(
Inheritance
) –> is-a- 子类(
derived class
)指向父类(base class
),空心三角 - 子类完全继承父类的数据
- 构造与析构与组合相同
base clas
s的dtor
必须是virtual
,否则会出现undefined behavior1
2
3
4
5
6
7
8
9
10
11struct _List_node_base
{
_List_node_base* _M_next;
_List_node_base* _M_prev;
};
template<typename _Tp>
struct _List_node
: public _List_node_base
{
_tp _M_data;
};
- 子类(
p11. 虚函数与多态
virtual
:non-virtual
: 不希望derived class
重新定义(override
)virtual
: 希望derived class
重新定义,自己已经有默认定义pure virtual
:derived class
一定要定义, 没有默认定义1
2
3
4
5
6
7
8class Shape {
public:
virtual void draw () const = 0; // pure virtual
virtual void error (const std::string& msg); // virtual, 子类可以定义更详细的error
int objectID () const; // non-virtual
};
class Rectangle: public Shape {...};
class Ellipse: public Shape {...};- 实际应用: (
template method
) 读取文件时, 除了文件内容不一样,其他的步骤都是一样的,所以其他的步骤都可以提前写好,子类来实现文件内容的读取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using namespace std;
class CDocument
{
public:
void OnFileOpen()
{
// 每个cout代表一个实际动作 (function)
cout << "dialog..." << endl;
cout << "check file status..." << endl;
cout << "open file ..." << endl;
Serialize();
cout << "close file..." << endl;
cout << "update all views..." << endl;
}
virtual void Serialize() { };
};
class CMyDoc : public CDocumnet
{
public:
virtual void Serialize()
{
cout << "CMyDoc::Serialize() << endl;"
}
};
int main ()
{
CMyDoc myDoc;
myDoc.OnFileOpen(); // 先调用CDocument::OnFileOpen(&myDoc), 在Serialize时调用myDoc的Serialize()
}