来自Stanley B.Lippman的《Essential C++》第四章重要内容的总结,第四章目录:
1、实现Class
Class声明
只有前置声明之后 才能有类指针的定义 或者 以此Class作为数据类型
calss Stack; //声明
...
Stack *pt = 0; //定义一个类指针
void pocess(const Stack&); //以Stack作为数据类型
Class定义
所有member function都必须在Class主体内进行声明,至于是否要同时进行定义,可以自由定义。如果定义在Class以外,用": :" 表示xx函数是xx类的一个member
2、 构造函数(constructor)和折构函数(destructor)
构造函数是用来初始化 date member的函数,constructor的函数名称必须与Class名称相同,没有返回值,可以被重载。
定义方法一:
class Triangular {
public:
Triangular(); //default constructors
Triangular(int len);
Triangular(int len, int beg_pos);
};
如果构造函数没有任何参数,有两种可能:
1、它不接受任何参数,有可能有参数但是参数在这个构造函数内已经被写死,不允许更改
2、为每个参数提供了默认值,这种有默认值的构造函数也可以作为default 构造函数
定义方法二:
成员初始化列表,欲赋值给member的数值被放在member名称后面的小括号中。
Trianglular::Triangular(int len, int bp):_name("Triangular")
{
_length = len > 0 ? len : 1;
_beg_pos = bp > 0 ? bp : 1;
_next = _beg_pos - 1;
}
折构函数 与构造函数相对,一旦某个class提供有destructor,当其object结束生命时,便会自动调用destructor处理善后。主要用来释放在constructor中或者对象生命周期中分配的资源。
3、mutable和const
对于const参数,编译器必须保证参数在程序运行过程中不会被修改。
凡是在class主体以外定义的,如果是一个const member function,那就必须同时在声明与定义中指定const。
class Triangular{
public:
int elem(int pos) const; //声明
...
};
int elem(int pos) const{
return _elem[pos-1]; //定义时也要指定const
}
mutable
如果_next被表示为mutable,那么可以宣称,对_next所做的改变不会破坏class object的常量性。
4、this指针
this指针在member function内用来指向其调用者,它可以让我们访问调用者的一切,下面提供copy函数的定义及调用。
Triangular& Triangular::copy(const Triangular &rhs) {
_length = rhs._length;
_begin_pos = rhs._begin_pos;
return *this;
}
tr1.copy(tr2); //调用,将tr2复制给tr1
5、静态类成员
静态成员数 static date member
静态成员数用来表示唯一的、可共享的member。它可以在同一类的所有对象中被访问。static date member在定义的时候它的名称必须附上class scope运算符。
class Triangular{
public:
//...
private:
static vector_elems; //static data member声明
};
//以下代码放在程序代码文件中,例如Triangular.cpp
vectorTriangular::_elems; //绝对不能丢,否则无法被编译器实现
静态成员函数
一般情形下,member function必须通过其类的某个对象来调用,但是对于静态成员函数可以直接调用,前提是利用class scope说明基于的类对象,且静态成员函数没有访问任何的non-static member。
Triangular tri; //定义一个Triangular对象,名字是tri
bool is_elem = tri.is_elem(ival); //调用function member
bool is_elem = Triangular::is_elem(ival); //如果is_elem是静态成员函数,可以直接调用
static bool is_elem(int); //在class内的函数声明
6、运算符重载
像定义member function那样来定义运算符,唯一的差别是它不用指定名称,只需要在运算符前加上关键字operator即可。
class Triangular_iterator{
public:
bool operator==(const Triangular_iterator&) const; //运算符重载声明
...
};
inline bool operator==(const Triangular_iterator &rhs) const{
return _index==rhs._inedx; //定义
}
if(trian1 == trian2)... //调用
运算符重载规则:
1、不能引入新的运算符;2、运算符函数列表中,必须至少有一个参数为Class类型;3、优先级不可改变
7、访问类的私有成员
任何类都可以将其他function或class指定friend,friend具备与class member function相同的访问权限,可以访问class 的私有成员。只需要在某个函数的原型上加上关键字friend,就可以将它声明为某个class的friend。
为了让定义成功通过编译,必须在声明之前,提供类的定义(使用的那个类),否则无法确定函数原型是否正确。
也可以把整个类作为另一个类的friend
class Triangular{
friend class Triangular_iterator;
...
};
如果能通过public member function来访问私有成员,那么就不必通过建立friend 关系。
8、function object
function object是一种提供有function call运算符“()”的class
bool operator()(int value) const; //声明
bool Lessthan::operator()(int value) const //定义
{
return value < _val;
}
for (int i = 0; i < vec.size(); i++) //调用
{
if (lt(vec[i]))
count++;
}
通常会把function object当作参数传给泛型算法
vector::const_iterator iter = vec.begin();
vector::const_iterator it_end = vec.end();
os << "elements less than" << lt.comp_val() << endl;
while ((iter = find_if(iter, it_end, lt)) != it_end) //把function object当作参数传给泛型算法
{
os << *iter << ' ';
++iter;
}
遇到的问题及总结
1、记录程序运行的时间(秒及毫秒)
//程序运行时间(秒)
#include
clock_t startTime, endTime;
startTime = clock(); //计时开始
...
endTime = clock(); //计时结束
cout << "time: " <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
//程序运行时间(毫秒)
#include
DWORD startTime = GetTickCount();//计时开始
....
DWORD endTime = GetTickCount();//计时结束
cout << "The run time is:" << endTime - startTime << "ms" << endl;
2、注释要规范,美观,体现结构
https://blog.csdn.net/weixin_42488570/article/details/80760849
两张注释对比
一)基本没有注释
二)结构清晰,明白易懂
3、 错误LNK2001无法解析的外部符号
参考这篇文章:https://blog.csdn.net/aaron121211/article/details/50384289
处理函数有可能没有被实现,成员数也有可能没有被实现,比如static vector