1.构造函数constructor和析构函数destructor
构造函数在函数定义后立刻执行,相当于是一种初始化过程,在object被实例化之前就执行。构造函数的函数名和类名相同(相当于是自己定义自己)
//e.g.
class Triangular{
public:
//...
private:
int _length;
int _beg_pos;
int _next;
int *_pmat;
}
//冒号后面的_name是成员初始化列表,直接赋予private初值
Triangular::Triangular(int len,int bp):_name("Triangular")
{
_length = len>0? len,1;
_beg_pos = bp>0? bp:1;
_next = _beg_pos -1;
}
inline Triangular::~Triangular()
{ //destructor常用来做资源释放
delete[]_pamt;
}
destrctor功能相反,绝不会有返回值也没有任何参数,由于参数列表是空的,因此也绝不可能被重载。常用来做资源释放。
2.成员逐一初始化
有时我们需要以某个class object作为另一个object的初值,例如:
Triangular tri1(8);
Triangular tri2 = tri1;
本例中的_length,_beg_pos,_next都会依次从tri1复制到tri2,这就是默认的成员逐一初始化。
但如果类中间有destructor析构函数,数组之类的数据容器就会被释放掉,但可能私有值的指针仍然指向那里,这样就会出错。
//e.g.
#include "Triangular.h"
Triangular trian(8);
//此时,constructor发生作用
{Triangular trian2 = trian;
//此处,进行default memberwise initializetion
//...在这里使用trian2
//此处trian2的desturctor发生作用
}
//...在这里使用mat
//此处,trian的destructor发生作用
解决方法:产生一个独立的数组副本,这样就可以对某个对象进行析构操作又不至于影响到另一个对象
//e.g.
Triangular::Triangular (const Triangular &rhs):_length(rhs._length),_next(rhs._next)
{ //对rhs._pmat所指的数组产生一份完全副本
int elem_cnt = _length * _next //我乱写的关系式,使用时满足正确的关系式即可
_pmat = new double [elem_cnt];//new double 动态分配内存大小数组容器.
for(int ix = 0;ix<elem_cnt;++ix)
_pamt[ix] = rhs._pmat[ix];
}
3.可变和不变 (const的用法)
比如说我们进行一个某个数列各元素的求和,我们必须保证trian在sum()中不会被修改,然而任何一次member function的调用都可能会更改trian的值,所以我们要在calss public中使用const
int sum(const Triangular &trian)
{
int _beg_pos = trian.beg_pos();
int length = trian.length();
int sum = 0;
for (int ix = 0; ix<length;++ix)
sum += trian.elem(beg_pos +ix);
return sum;
}
根据sum来定义类Triangular
//e.g.
class Triangular{
public:
//以下是const member function
int length() const {return _length;}
int beg_pos() const{return _beg_pos;}
int elem(int pos ) const;
//以下是non-const member function
bool next(int &val);
viod net_reset(){_next = _beg_pos -1;}
private:
int _length;//元素个数
int _beg_pos;//起始位置
int _next;//下一个迭代目标
//static data member
static std::vector<int>_elems;
};
在定义const时,必须考虑到member function完全不更改class object的任何值
4.This 指针
是一个指向对象的指针
this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到参数列表中。
this 作为隐式形参,本质上是成员函数的局部变量,所以只能用在成员函数的内部,并且只有在通过对象调用成员函数时才给 this 赋值。
Triangular tr1(8);
Triangular tr2(8.9);
tr1.copy(tr2)//把tr2的各项数据传给tr1
//e.g. 以一个对象复制出另一个对象
Triangular & Triangular::copy(const Triangular &rhs)
{//检查两个对象是否相同
if(this != &rhs)
{
_length = rhs._length;
_beg_pos = rhs._beg_pos;
_next = _rhs._beg_pos -1 ;
}
return *this;
}
上例中,this是指向tr1的指针,*this则是返回所指的对象本身。
5.静态成员函数
直观理解:静态成员函数时一种与类紧密连接的全局变量,让某种属性或算法称为该类(多类也是可以的)所共用的,一般来说,类内声明一次后,类外要定义/初始化一次。
//Triangular.h
#pragma once
#include <string>
#include <vector>
#include <iostream>
class Triangular
{
public:
Triangular(int len,int beg_pos);
//结构函数
static bool is_elem(int elem);
static void gen_elements(int length);
static void gen_elems_to_value(int value);
//static void display(int length, int beg_pos, std::ostream &os = std::cout);
private:
std::string _name;
int _next, _length, _beg_pos;
static std::vector<int> _elems;//静态成员只有唯一实体
static const int _max_elems = 1024;
};
std::vector<int> Triangular::_elems;//类外定义一次
//member intialization list 成员初始化列表 :后表示给某些项赋值
Triangular::Triangular(int len, int bp) : _name("Triangular") {
_length = len > 0 ? len : 1;
_beg_pos = bp > 0 ? bp : 1;
_next = _beg_pos - 1;
}
bool Triangular::is_elem(int value)
{
if (!_elems.size() || _elems[_elems.size() - 1] < value)
gen_elems_to_value(value);
std::vector<int>::iterator found_it;
std::vector<int>::iterator end_it = _elems.end();
found_it = std::find(_elems.begin(), end_it, value);
return found_it != end_it;
}
void Triangular::gen_elems_to_value(int value)
{
int ix = _elems.size();
if (!ix) {
_elems.push_back(1);
ix = 1;
}
while (_elems[ix -1 ]<value && ix<_max_elems)
{
std::cout << "elems to value:" << ix*(ix + 1) / 2 << std::endl;
++ix;
_elems.push_back(ix*(ix + 1) / 2);
}
if (ix == _max_elems)
std::cerr << "value too large" << value << "exceeds max size of " << _max_elems << std::endl;
}
void Triangular::gen_elements(int length)
{
if (length<0 || length>_max_elems) {
//发出错误信息然后直接返回
}
if (_elems.size() < length)
{
int ix = _elems.size() ? _elems.size() + 1 : 1;
for (; ix <= length; ++ix)
_elems.push_back(ix*(ix + 1) / 2);
}
}
//cpp程序
#include "Triangular.h"
#include <string>
#include <iostream>
#include <vector>
int main() {
char ch;
bool more = true;
while (more)
{
std::cout << "enter value:";
int ival;
std::cin >> ival;
bool is_elem = Triangular::is_elem(ival);
std::cout << ival << (is_elem ? "is" : "is not " )
<< "an element in the Triangular series.\n"
<< "Another value?(y/n)";
std::cin >> ch;
if (ch == 'n' || ch == 'N')
more = false;
}
}
6.重写运算符
#pragma once
#include <vector>
#include <iostream>
class Triangular
{
public:
//...
friend std::ostream & operator<<(std::ostream& os, const Triangular& t);
private:
//...
};
std::ostream& operator<<(std::ostream& os, const Triangular& t) {
os << "(" << t.length() << "," << t.beg_pos() << ")";
return os;
}
//...
7.友元函数
一个类为了方位另一个类的私有,可以通过友元函数的形式(或者直接在public里面写一个专门的函数直接返回私有,这样别的类就可以通过调用函数的形式返回了)。
友元函数有两种形式,一种是声明一个函数是friend性质的。例如
//e.g.
class Triangular{
private:
friend int Triangular_iterator::operator*();
friend void Triangular_iterator::check_integrity();
}
上例中,Triangular_iterator要访问Triangular的私有,所以在Triangular中声明Triangular_iterator的这两个函数是他的朋友,朋友就可以访问私有的。
第二种形式,直接声明一个类是另一个类的私有。
class Triangular{
private:
friend class Triangular_iterator;
}
8.定义operator
如果想定义一个操作符,需要在操作符之前加上operator关键字。以下将以复制(即等于号,把A的对象a的值赋给对象b)
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;
}
其中matrix&是返回类型, matrix::operator代表我定义的操作符是matrix这个类的,等于号相当于函数名,接收一个右侧参数,都是以传地址的方式来输入输出的。最后返回this指针所指向的对象。
*this返回rhs(输入右值)的长度和起始位置。(因此也是个地址,所以一开始要写matrix&),this等于说是个指向地址的指针。
9.创建一个function object运算符
当编辑器遇到形如
lt.(ival)时,这个lt可能是个函数名称,可能是函数指针,也有可能是个提供function call运算符的function object。如果是这样,那么编辑器会在内部将此语句转化为
lt.operator(ival);
具体例子如下:
//e.g.
//LessThan.h头文件
#pragma once
#include <vector>
#include <iostream>
#include <algorithm>
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 std::vector<int> &vec, int comp)
{
LessThan lt(comp);
int count = 0;
for (int ix = 0; ix < vec.size(); ++ix)
if (lt(vec[ix])) //这里就是使用了function object
//使得vec[ix]小于comp即返回true
++count;
return count;
}
void print_less_than(const std::vector<int> &vec, int comp, std::ostream &os = std::cout)
{
LessThan lt(comp);
std::vector<int>::const_iterator iter = vec.begin();
std::vector<int>::const_iterator it_end = vec.end();
os << "elements less than" << lt.comp_val() << std::endl;
//一种高效简洁的while的写法
while ((iter = find_if(iter,it_end,lt))!=it_end)
{
os << *iter << " ";
++iter;
}
}
mian程序
#include "LessThan.h"
#include <iostream>
int main()
{
int ia[16] = { 17,12,44,9,18,45,6,14,
34,67,9,0,27,55,8,16 };
std::vector<int> vec(ia, ia + 16);
int comp_val = 20;
std::cout << "number of elements less than" << comp_val << "are"
<< count_less_than(vec, comp_val) << std::endl;
print_less_than(vec, comp_val);
getchar();
}
本文深入探讨C++中的构造函数与析构函数,解释它们的作用与应用场景,包括成员初始化、拷贝构造、const使用、this指针、静态成员函数、运算符重载及友元函数等内容。
1360

被折叠的 条评论
为什么被折叠?



