继上篇的文章《Essential C++ 笔记(4):基于对象的编程风格(上)》,继续更新Essential C++ 笔记。
任何class
均可以将其他函数或其他类指定为它的朋友(friend)。所谓的friend
就具备了和类成员函数相同的访问权限。在类的内部必须是将非成员函数设为朋友。
class Triangular {
friend int operator*(const Triangular_iterator &rhs);
};
class Triangular_iterator {
friend int operator*(const Triangular_iterator &rhs);
};
//类的外部定义
inline int operator*(const Triangular_iterator &rhs){
rhs.check_integrity(); // 可以直接访问类的私有成员
return Triangular_iterator::_elems[rhs.index()]; // 可以直接访问类的私有成员
}
可以先令A类与B类建立友元关系,让A类的所有成员函数称为B类的友元。
class Triangular {
//Triangular_iterator中的所有成员函数都是Triangular中的友元。
friend class Triangular_iterator;
};
下面的代码属于默认的成员逐一赋值操作:
Triangular tri1(8), tri2(8, 9);
tri1 = tri2;
但对于第二节中的Matrix类,上述拷贝过程只是浅拷贝,我们需要的是深拷贝,这时需要一个拷贝构造函数和一个拷贝赋值运算符:
Matrix& Matrix::operator=(const Matrix &rhs){
if(this != &rhs){
_row = rhs._row;
_col = rhs._col;
int elem_cnt = _row * _col;
delete [] _pmat;
_pmat = new double[elem_cnt];
for(int ix = 0; ix < elem_cnt; ix++)
_pmat[ix] = rhs._pmat[ix];
}
return *this;
}
编译器在编译过程中遇到函数调用,例如:
It(ival);
It
可能是函数名,可能是函数指针,也可能是提供了仿函数(function call)运算符的函数对象。
仿函数运算符可以接收任意个数的参数。举个例子,测试传入值是否小于某测试值。
class LessThan{
public:
LessThan(int val) : _val(val) {} //成员初始化列表
int comp_val() const{
return _val; // 基值的读取
}
void comp_val(int nval){
_val = nval;// 基值的写入
}
bool operator()(int _value) const;
private:
int _val;
};
//仿函数运算符实现如下
inline bool LessThan::operator()(int value) const{
return value < _val;
}
将仿函数运算符应用到对象身上,便可调用仿函数运算符:
int count_less_than(const vector<int> &vec, int comp){
LessThan It(comp);
int count = 0;
for(int ix = 0; ix < vec.size(); ix++)
if(It(vec[ix]))
count++;
return count;
}
通常将函数对象当做参数传给泛型算法:
void print_less_than(const vector<int>& vec, int comp, ostream &os = cout){
LessThan It(comp);
vector<int>::const_iterator iter = vec.begin();
vector<int>::const_iterator it_end = vec.end();
os << "elements less than " << It.comp_val() << endl;
while((iter != find_if(iter, it_end, It)) != it_end){
os << *iter << ' ';
++iter;
}
}
如果想要读取和写入类对象的值,我们希望cout << trian << endl;
这样写,所以需要重载output运算符操作:
ostream& operator<<(ostream &os, const Triangular &rhs){
os << "(" << rhs.beg_pos() << ", " << rhs.length() << " )";
rhs.display(rhs.length(), rhs.beg_pos(), os);
return os;
}
// 实现如下:
Triangular tri( 6, 3 );
cout << tri << endl;
// 结果:
// ( 3, 6 ) 6 10 15 21 28 36
使用一个通用的数列类num_sequence
,使其对象可同时支持多种数列:
int main(){
num_sequence ns;
const int pos = 8;
for(int ix = 0; ix < num_sequence::num_of_sequence(); ++ix){
ns.set_sequence(num_sequence::ns_type(ix));
int elem_val = ns.elem(pos);
display(cout, ns, pos, elem_val);
}
}
指向成员函数的指针,要指定它所指向的是什么类:
void (num_sequence::*pm)(int) = 0;
该程序就是将pm
声明为一个指针,指向num_sequence
的成员函数,返回类型是void
,只接受一个类型为int
的参数。pm
初始值为0
,表示目前不指向任何成员函数。
可以对上述代码进行简化:
typedef void (num_sequence::*PtrType)(int);
PtrType pm = 0;
num_sequence
提供下述六个成员函数,每一个都可由PtrType
指针加以定位:
class num_sequence{
public:
typedef void (num_sequence::*PtrType)(int);
void fibonacci(int);
void pell(int);
void lucas(int);
void triangular(int);
void sequence(int);
void pentagonal(int);
private:
PtrType _pmf;
};
如果需要定义一个指针,指向成员函数fibonacci()
:
PtrType pm = &num_sequence::fibonacci;
可以将六个成员函数的地址存储到一个static array
中。再维护一个vector
,存储各个数列:
class num_sequence{
public:
typedef void (num_sequence::*PtrType)(int);
//...
private:
vector<int>* _elem; // 指向目前所用的vector
PtrType _pmf; //指向目前所用的算法(用以计算数列的元素)
static const int num_seq = 7;
static PtrType func_tbl[num_seq];
static vector<vector<int> > seq;
};
接下来提供每个静态成员函数的定义:
const int num_sequence::num_seq;
vector<vector<int> > num_sequence::seq(num_seq);
num_sequence::PtrType num_sequence::func_tbl[num_seq] = {
0,
&num_sequence::fibonacci,
&num_sequence::pell,
&num_sequence::lucas,
&num_sequence::triangular,
&num_sequence::sequence,
&num_sequence::pentagonal
};
_elem()
和_pmf
在set_sequence()
中一起被设定,前者指向存有数列元素的vector
,后者指向产生数列元素的成员函数。
指向成员函数和指向函数的指针的一个不同点就是,前者必须通过同一类的对象加以调用,该对象便是成员函数中的this
指针所指之物。假设如下定义:
num_sequence ns;
num_sequence *pns = &ns;
PtrType pm = &num_sequence::fibonacci;
通过ns
调用_pmf
:
// 和 ns.fibonacci(pos) 相同
(ns.*pm)(pos)
// 和 pns->fibonacci(pos)相同
(pns->*pm)(pos)
下面是elem()
函数的实现内容:
int num_sequence::elem(int pos){
if(!check_integrity(pos))
return 0;
if(pos > _elem->size())
(this->*_pmf)(pos);
return (*_elem)[pos - 1];
}
以上便是该书的第四章内容,下篇更新第五章的内容,to be continued…