当前位置: 首页> 汽车> 行情 > 高端网站建设的要求_营销网站的设计与实现_线上营销的方式_开发网站多少钱

高端网站建设的要求_营销网站的设计与实现_线上营销的方式_开发网站多少钱

时间:2025/7/11 14:55:17来源:https://blog.csdn.net/weixin_52288941/article/details/146924127 浏览次数: 0次
高端网站建设的要求_营销网站的设计与实现_线上营销的方式_开发网站多少钱

c++是函数名+类型的。

函数模板

C++函数模板,
模板的意义,对类型也可以进行参数化了。

template<typename T>//定义一个模板参数列表
bool compare(T a,T b) //compare是一个函数模板
{return a>b;
}

函数模板的实例化

在函数调用点进行实例化

/*
实例化的整型模板函数
bool compare<int>(int a,int b)
{return a>b;
}
bool compare<double>(double a,double b)
{return a>b;
}
*/
int main()
{//在函数调用点,编译器根据用户指定的类型,从原模版实例化一份代码出来//叫做模板函数compare<int> (10,20);compare<double>(10.5,20.5);
}

函数模板的实参推演

compare(20,30);//根据传入的实参的类型,推导出模板函数类型

函数模板的特例化

/*针对compare这个模板函数,能适用于大部分数据类型,如int ,double,以及对象,但是也有特例
如compare("aaa","bbb"),根据函数推演,其应该是
bool <const char *>(const char *,const char *)
{
return a<b;
}
这样比较的是a和b两个地址的大小,而非字典序大小,
针对这种情况,提供const char *这个类型的特例化版本
*/
template<>
bool compare(const char *a,const char *b)
{return strcmp(a,b)>0;
}

非模板函数-普通函数

//template<> //没有这个template定义的就是普通函数
bool compare(const char *a,const char *b)
{return a<b;
}

注意:模板代码是不能在一个文件中定义,在另外一个文件中使用的。模板代码调用之前,一定要看到模板定义的地方,这样模板才能够正常的实例化,产生能够被编译器编译的代码。所以,一般模板代码都是放在头文件中的。
不过如果是跨文件调用的化,在该函数模板定义的文件中,告诉编译器进行指定类型的模板实例化也是可以的(这种一般不推荐,要手动初始化多个类型的模板函数)。

类模板

template <typename T>
class SeqStack //模板名称+类型参数列表=类名称
{
public://构造和析构函数不用加<T>(在类里面,就是类模板)//但是其他出现模板的地方都加上类型参数列表SeqStack(int size=10):_pstack(new T[size]),_top(0),_size(size){}~SeqStack(){delete []_stack;_pstack=nullptr;}SeqStack(const SeqStack<T> &stack) //重载拷贝构造运算符:_top(stack._top),_size(stack._size){_pstack=new T[_size];//memcopy是浅拷贝,一般仅用于一些内置类型,对于对象等一般for循环赋值for (int i=0;i<_top;++i){_pstack[i]=stack._pstack[i];}}SeqStack<T> &operator=(const SeqStack<T> &stack) //重载赋值运算符{if (this==&stack) //防止自赋值,return *this;delete []_pstack;//删除其指向的原有数据堆_top=stack._top;_size=stack._size;//这部分跟拷贝构造执行的一样_pstack=new T[_size];for (int i=0;i<_top;++i){_pstack[i]=stack._pstack[i];}return *this;}void push(const T &val) //入栈操作{if (full())expand();_pstack[_top++]=val;}void pop(){if(empty())return;--top;}T top() const{if (empty())throw "stack is empty"; //抛出异常return _pstack[_top-1];}bool full() const {return _top==_size;}bool empty() const {return _top==0; }
private:T *_pstack;  //这个指向了外部资源,堆区,要使用深拷贝int _top;int _size;//顺序栈底层数组按2倍方式扩容void expand(){T *ptmp=new T[_size*2];for (int i=0;i<_top;++i){ptmp[i]=_pstack[i];}delete []_pstack;_pstack=ptmp;_size*=2;}}

使用类模板实现vector

在这里插入图片描述

template<typename T>
class vector
{
public:vector(int size = 10){_first = new T[size];_last = _first;_end = _first + size;}~vector(){delete[]_first;_first = _last = _end = nullptr;}vector(const vector<T>& cp){int size = cp._end - cp._first;_first = new T[size];int len = cp._last - cp._first;for (int i = 0; i < len; i++){_first[i] = cp._first[i];}_last = _first + len;_end = _first + size;}vector<T>& operator=(const vector<T>& cp){if (this == &cp)return*this;delete[]_first;int size = cp._end - cp._first;_first = new T[size];int len = cp._last - cp._first;for (int i = 0; i < len; i++){_first[i] = cp._first[i];}_last = _first + len;_end = _first + size;return *this;}void push_back(const T& val){if (full())expand();*_last++ = val;}void pop_back(){if (empty())return;--_last;}T back() const{if (empty())throw "stack is empty"; //抛出异常return *(_last - 1);}bool empty() const{ return _first == _last;	}bool full() const { return _last == _end;}int getsize() const { return _last - _first; }
private:T* _first; //指向数组起始的位置T* _last;  //指向数组中有效元素的后继位置T* _end;  //指向数组的结尾void expand(){int size = _end - _first;T* ptmp = new T[2 * size];for (int i = 0; i < size; i++){ptmp[i] = _first[i];}delete[]_first;_first = ptmp;_last = _first + size;_end = _first + 2 * size;}
};

容器空间配置器

上一节实现了vector的类模板,但是存在以下问题。

1.在初始化的时候,开辟内存和对象构造是一起执行的;但是一般是不需要默认的构造的,这样会带来开销,构造和析构带来的。

class Test
{
public:Test() { cout << "Test()" << endl; }~Test() { cout << "~Test()" << endl; }Test (const Test& ){cout << "拷贝构造"<<endl;}Test& operator= (const Test& cp){cout << "赋值构造" << endl;return *this;}
};
int main()
{	Test t1, t2, t3;vector<Test> vec;			//创建一个大小为size的空间,但是已经被空对象占据了位置cout << vec.getsize() << endl; //有效空间为0vec.push_back(t1);         //这里调用的是赋值构造函数,说明该处原来有值vec.push_back(t2);vec.push_back(t3);cout << vec.getsize() << endl; //有效空间为3vec.pop_back();cout << vec.getsize() << endl; //有效空间为2return 0;//在函数结束的时候析构空对象,增加计算负担
}/*输出
这里有10个对象的区域,一开始就被空的对象占据了,浪费资源(构造和析构资源)
*/

2.之前实现vector版本中pop_back是指针回退,但是如果仅仅是回退的话,万一指向的test指向其他外部资源,单纯的回退会导致这一部分资源无法管理,导致空间浪费

class Test
{
public:Test(){_ps=new int[5];}~Test() { delete []_ps;_ps=nullptr;}private:int *_ps;
};//如果仅仅是指针回退,而不析构对应的对象的话,会造成管理的外部资源泄露

空间配置器实现

容器的空间配置器allocator做四件事情:内存开辟/内存释放 对象构造/对象析构
将内存开辟与对象构造、内存释放与对象析构分开来

template <typename T>
struct Allocator
{T* allocate(size_t size)  //负责内存开辟{return (T*)malloc(sizeof(T) * size);}void deallocate(void* p) //负责内存释放{free(p);}void construct(T* p, const T& val) //负责对象构造{new (p) T(val);  //定位new,负责在指定位置构造对象}void destroy(T* p)   //负责对象析构{p->~T();  //~T()代表了T类型的析构函数}
};/*
* 容器底层开辟内存,释放内存,对象析构和构造,都通过allocator空间配置器实现
*/
template<typename T,typename Alloc=Allocator<T>>
class vector
{
public:vector(int size = 10){	//需要把内存开辟和对象构造分开处理//_first = new T[size];_first = _allocator.allocate(size);_last = _first;_end = _first + size;}~vector(){	//析构容器有效的元素,然后释放_first指针指向的堆内存//delete[]_first;for (T* p = _first; p != _last; p++){_allocator.destroy(p);     //把_first指针指向的数组有效元素进行析构操作}_allocator.deallocate(_first); //释放堆上的数组内存_first = _last = _end = nullptr;}vector(const vector<T>& cp){int size = cp._end - cp._first;//_first = new T[size];_first = _allocator.allocate(size);int len = cp._last - cp._first;for (int i = 0; i < len; i++){//_first[i] = cp._first[i];_allocator.construct(_first + i, cp._first);}_last = _first + len;_end = _first + size;}vector<T>& operator=(const vector<T>& cp){if (this == &cp)return*this;delete[]_first;int size = cp._end - cp._first;//_first = new T[size];_first = _allocator.allocate(size);int len = cp._last - cp._first;for (int i = 0; i < len; i++){//_first[i] = cp._first[i];_allocator.construct(_first + i, cp._first);}_last = _first + len;_end = _first + size;return *this;}void push_back(const T& val){if (full())expand();//*_last++ = val; //last指针指向的内存构造一个值为val的对象_allocator.construct(_last, val); _last++;}void pop_back(){if (empty())return;//--_last;//不仅要把_last指针--,还要析构删除的元素,因为有可能指向外部资源,如堆区--_last;_allocator.destroy(_last);}T back() const{if (empty())throw "stack is empty"; //抛出异常return *(_last - 1);}bool empty() const{ return _first == _last;	}bool full() const { return _last == _end;}int getsize() const { return _last - _first; }
private:T* _first; //指向数组起始的位置T* _last;  //指向数组中有效元素的后继位置T* _end;  //指向数组的结尾Alloc _allocator; //定义容器的空间配置器对象void expand(){int size = _end - _first;//T* ptmp = new T[2 * size];T* ptmp = _allocator.allocate(2 * size);for (int i = 0; i < size; i++){//ptmp[i] = _first[i];_allocator.construct(ptmp + i, _first[i]);}//delete[]_first;for (T* p = _first; p != _last; p++){_allocator.destroy(p);     //把_first指针指向的数组有效元素进行析构操作}_allocator.deallocate(_first); //释放堆上的数组内存_first = ptmp;_last = _first + size;_end = _first + 2 * size;}
};int main()
{	Test t1, t2, t3;vector<Test> vec;cout << vec.getsize() << endl;vec.push_back(t1);vec.push_back(t2);vec.push_back(t3);cout << vec.getsize() << endl;vec.pop_back();cout << vec.getsize() << endl;return 0;
}/*
Test()
Test()
Test()
0
拷贝构造
拷贝构造
拷贝构造
3
~Test()
2
~Test()
~Test()
~Test()
~Test()
~Test()
*/
关键字:高端网站建设的要求_营销网站的设计与实现_线上营销的方式_开发网站多少钱

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: