当前位置: 首页 > wzjs >正文

手机网站建设可行性分析福州在线

手机网站建设可行性分析,福州在线,软件项目开发流程和步骤,公司手机网站建设文章目录 5. 新的类功能5.1 默认的移动构造和移动赋值5.2 成员变量声明时给缺省值5.3 defult和delete5.4 final与override 6. 可变参数模板6.1 基本语法及原理6.2 包扩展6.3 empalce系列接口list实现empalce 5. 新的类功能 5.1 默认的移动构造和移动赋值 原来C类中&#xff0c…

文章目录

  • 5. 新的类功能
    • 5.1 默认的移动构造和移动赋值
    • 5.2 成员变量声明时给缺省值
    • 5.3 defult和delete
    • 5.4 final与override
  • 6. 可变参数模板
    • 6.1 基本语法及原理
    • 6.2 包扩展
    • 6.3 empalce系列接口
        • list实现empalce


5. 新的类功能

5.1 默认的移动构造和移动赋值

  • 原来C++类中,有6个默认成员函数:构造函数/析构函数/拷贝构造函数/拷贝赋值重载/取地址重载/const 取地址重载,最后重要的是前4个,后两个用处不大,默认成员函数就是我们不写编译器会生成一个默认的。C++11 新增了两个默认成员函数,移动构造函数和移动赋值运算符重载。
  • 如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。
  • 如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)
  • 如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。
class Person
{
public:// 构造函数// const char* name = "" 默认参数为空字符串// int age = 0 默认参数为0// 初始化列表初始化成员变量_name和_agePerson(const char* name = "", int age = 0):_name(name), _age(age){}// 拷贝构造函数// 参数为const引用,避免修改传入对象// 初始化列表完成深拷贝/*Person(const Person& p):_name(p._name),_age(p._age){}*/// 赋值运算符重载// 返回引用以支持连续赋值// 检查自赋值// 深拷贝所有成员/*Person& operator=(const Person& p){if(this != &p){_name = p._name;_age = p._age;}return *this;}*/// 析构函数// 成员变量的析构函数会自动调用/*~Person(){}*/private:bit::string _name;  // 姓名,string类型int _age;          // 年龄,整型
};int main()
{Person s1;                  // 调用构造函数,默认构造Person s2 = s1;            // 调用拷贝构造(编译器生成的默认版本)Person s3 = std::move(s1); // 调用移动构造(编译器生成的默认版本)Person s4;                 // 调用构造函数,默认构造s4 = std::move(s2);       // 调用移动赋值运算符(编译器生成的默认版本)return 0;
}

5.2 成员变量声明时给缺省值

成员变量声明时给缺省值是给初始化列表用的,如果没有显示在初始化列表初始化,就会在初始化列表用这个却绳子初始化,这个在类和对象部分讲过了,忘了就去复习。


5.3 defult和delete

  • C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用default关键字显示指定移动构造生成。
  • 如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补丁已,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。
class Person
{
public:// 构造函数// const char* name = "" 默认参数为空字符串// int age = 0 默认参数为0// 使用参数构造bit::string对象_name,直接赋值给_agePerson(const char* name = "", int age = 0):_name(name), _age(age){}// 拷贝构造函数// 对传入对象p进行深拷贝// 会调用bit::string的拷贝构造函数完成_name的深拷贝// _age直接赋值拷贝Person(const Person& p):_name(p._name),_age(p._age){}// 移动构造函数// = default表示使用编译器生成的默认版本// 会调用bit::string的移动构造函数,转移_name的资源所有权// _age直接按位拷贝Person(Person&& p) = default;// 如果打开这个注释,会禁用拷贝构造// 禁用后,对象将不能进行拷贝构造,只能进行移动构造//Person(const Person& p) = delete;private:bit::string _name;  // 姓名int _age;          // 年龄
};int main()
{Person s1;                  // 调用默认构造函数Person s2 = s1;            // 调用拷贝构造函数,深拷贝s1Person s3 = std::move(s1); // 调用移动构造函数,转移s1的资源// 转移后s1的_name应该被置空return 0;
}

5.4 final与override

这个在继承和多态章节已经进行了详细讲过了,忘了就去复习。


6. 可变参数模板

6.1 基本语法及原理

  • C++11支持可变参数模板,也就是说支持可变数量参数的函数模板和类模板,可变数目的参数被称为参数包,存在两种参数包:模板参数包,表示零或多个模板参数;函数参数包:表示零或多个函数参数。
  • template <class ...Args> void Func(Args... args) {}
  • template <class ...Args> void Func(Args&... args) {}
  • template <class ...Args> void Func(Args&&... args) {}
  • 我们用省略号来指出一个模板参数或函数参数的表示一个包,在模板参数列表中,class...typename...指出接下来的参数表示零或多个类型列表;在函数参数列表中,类型名后面跟…指出接下来表示零或多个形参对象列表;函数参数包可以用左值引用或右值引用表示,跟前面普通模板一样,每个参数实例化时遵循引用折叠规则。
  • 可变参数模板的原理跟模板类似,本质还是去实例化对应类型和个数的多个函数。
  • 这里我们可以使用sizeof...运算符去计算参数包中参数的个数。
// 可变参数模板函数
// Args&&... 是参数包,可以接受任意数量、任意类型的参数
// Args&&是万能引用,可以接受左值和右值
template <class ...Args>
void Print(Args&&... args)
{// sizeof...(args)返回参数包中参数的个数cout << sizeof...(args) << endl;
}int main()
{double x = 2.2;Print();                              // 参数包为空Print(1);                             // 参数包含一个右值1Print(1, string("xxxxx"));            // 参数包含右值1和右值stringPrint(1.1, string("xxxxx"), x);       // 参数包含右值1.1、右值string和左值xreturn 0;
}// 原理1:编译器会根据实际调用展开成以下具体函数
// 根据引用折叠规则:
// - 右值传入时,T&&折叠为右值引用
// - 左值传入时,T&&折叠为左值引用
void Print();                                                 // 对应Print()
void Print(int&& arg1);                                      // 对应Print(1)
void Print(int&& arg1, string&& arg2);                       // 对应Print(1, string("xxxxx"))
void Print(double&& arg1, string&& arg2, double& arg3);      // 对应Print(1.1, string("xxxxx"), x)// 原理2:如果没有可变参数模板,就需要手动写很多重载版本
// 为了支持不同数量的参数,需要写很多函数模板
void Print();template <class T1>
void Print(T1&& arg1);template <class T2, class T2>
void Print(T1&& arg1, T2&& arg2);template <class T1, class T2, class T3>
void Print(T1&& arg1, T2&& arg2, T3&& arg3);
// ... 需要写更多重载来支持更多参数// 可变参数模板的优势:
// 1. 一个模板就能处理任意数量参数
// 2. 通过参数包和引用折叠,实现了完美转发
// 3. 大大减少了代码量

6.2 包扩展

  • 对于一个参数包,我们除了能计算他的参数个数,我们能做的唯一的事情就是扩展它,当扩展一个包时,我们还要提供用于每个扩展元素的模式,扩展一个包就是将它分解为构成的元素,对每个元素应用模式,获得扩展后的列表。我们通过在模式的右边放一个省略号(…)来触发扩展操作。底层的实现细节如图1所示。
  • C++还支持更复杂的包扩展,直接将参数包依次展开依次作为实参给一个函数去处理。

19a214249011e9f1802ffe2624d1ff70

代码1:

// ================== 不可行的实现方式 ==================
template <class ...Args>
void Print(Args... args)
{// 这种实现方式是错误的,原因:// 1. 可变参数模板是在编译时展开的// 2. 无法在运行时通过下标访问参数包// 3. args不是一个数组,不支持下标访问cout << sizeof...(args) << endl;  // sizeof...是编译时操作符for (size_t i = 0; i < sizeof...(args); i++){cout << args[i] << " ";   // 错误:参数包不支持下标访问}cout << endl;
}// ================== 正确的递归实现 ==================
// 递归终止函数
// 当参数包为空时的特化版本
void ShowList()
{cout << endl;  // 仅打印换行
}// 递归展开函数
template <class T, class ...Args>
void ShowList(T x, Args... args)
{cout << x << " ";       // 处理第一个参数ShowList(args...);      // 递归处理剩余参数// args... 是参数包展开,将剩余参数传递给下一次递归调用
}// 包装函数,提供更简洁的接口
template <class ...Args>
void Print(Args... args)
{ShowList(args...);   // 转发所有参数到ShowList
}int main()
{// 测试各种参数数量的调用Print();                             // 调用空参数版本Print(1);                            // 调用一个参数版本Print(1, string("xxxxx"));           // 调用两个参数版本Print(1, string("xxxxx"), 2.2);      // 调用三个参数版本return 0;
}// ================== 编译器展开示例 ==================
// 对于 Print(1, string("xxxxx"), 2.2) 的调用
// 编译器会将模板展开为以下具体函数:// 第一层展开
void ShowList(int x, string y, double z)
{cout << x << " ";      // 打印1ShowList(y, z);        // 继续递归
}// 第二层展开
void ShowList(string x, double z)
{cout << x << " ";      // 打印"xxxxx"ShowList(z);           // 继续递归
}// 第三层展开
void ShowList(double x)
{cout << x << " ";      // 打印2.2ShowList();            // 调用终止函数
}// 最终调用基础版本
void ShowList()
{cout << endl;          // 打印换行,结束递归
}// Print函数相应展开为:
void Print(int x, string y, double z)
{ShowList(x, y, z);     // 调用展开后的ShowList
}

代码2:

// 特化版本:处理无参数的情况
void CppPrint()
{cout << endl;  // 只打印换行
}// 辅助函数:打印单个参数并返回0
// 返回0是为了配合数组初始化方式展开参数包
template <class T>
int PrintArg(T t)
{cout << t << " ";  // 打印参数return 0;          // 返回0用于数组初始化
}// 可变参数模板函数
// 使用数组初始化的方式展开参数包
template <class ...Args>
void CppPrint(Args... args)
{// 这行代码完成了参数包的展开// PrintArg(args)... 会展开为 PrintArg(arg1), PrintArg(arg2), ...// 使用数组初始化列表,确保按顺序展开和执行int a[] = { PrintArg(args)... };cout << endl;  // 最后打印换行
}int main()
{// 测试不同数量参数的调用CppPrint();                              // 调用无参数版本CppPrint(1);                             // 调用一个参数版本CppPrint(1, 2);                          // 调用两个参数版本CppPrint(1, 2, 2.2);                     // 调用三个参数版本CppPrint(1, 2, 2.2, string("xxxx"));     // 调用四个参数版本return 0;
}

代码3:

// Date类定义
class Date
{
public:// 构造函数,使用默认参数// 支持传入0-3个参数的构造Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){cout << "Date构造" << endl;}// 拷贝构造函数// 用于通过已有Date对象构造新对象Date(const Date& d):_year(d._year), _month(d._month), _day(d._day){cout << "Date拷贝构造" << endl;}private:int _year;int _month;int _day;
};// 可变参数模板工厂函数
// 用于创建Date对象,可接收0-3个参数
template <class ...Args>
Date* Create(Args... args)
{// 将参数包完美转发给Date的构造函数Date* ret = new Date(args...);return ret;
}int main()
{// 测试不同参数数量的对象创建Date* p1 = Create();              // 调用无参构造:Date(1, 1, 1)Date* p2 = Create(2023);          // 调用单参构造:Date(2023, 1, 1)Date* p3 = Create(2023, 9);       // 调用双参构造:Date(2023, 9, 1)Date* p4 = Create(2023, 9, 27);   // 调用三参构造:Date(2023, 9, 27)Date d(2023, 1, 1);               // 创建一个Date对象Date* p5 = Create(d);             // 通过拷贝构造创建新对象return 0;
}

6.3 empalce系列接口

  • template <class... Args> void emplace_back (Args&&... args);
  • template <class... Args> iterator emplace (const_iterator position, Args&&... args);
  • C++11以后STL容器新增了empalce系列的接口,empalce系列的接口均为模板可变参数,功能上兼容pushinsert系列,但是empalce还支持新玩法,假设容器为container<T>empalce还支持直接插入构造T对象的参数,这样有些场景会更高效一些,可以直接在容器空间上构造T对象。
  • emplace_back总体而言是更高效,推荐以后使用emplace系列替代insertpush系列
  • 第二个程序中我们模拟实现了listemplaceemplace_back接口,这里把参数包不段往下传递,最终在结点的构造中直接去匹配容器存储的数据类型T的构造,所以达到了前面说的empalce支持直接插入构造T对象的参数,这样有些场景会更高效一些,可以直接在容器空间上构造T对象。
  • 传递参数包过程中,如果是 Args&&... args 的参数包,要用完美转发参数包,方式如下std::forward<Args>(args)... ,否则编译时包扩展后右值引用变量表达式就变成了左值。

代码1:

#include<list>int main()
{list<bit::string> lt;// 1.传入左值的情况bit::string s1("111111111111");lt.emplace_back(s1);  // 会调用拷贝构造,和push_back效果一样cout << "*********************************" << endl;// 2.传入右值的情况lt.emplace_back(move(s1));  // 会调用移动构造,和push_back效果一样cout << "*********************************" << endl;// 3.直接传入构造string需要的参数lt.emplace_back("111111111111");  // 直接在list节点空间构造string对象// 避免了先构造临时对象再拷贝/移动的过程// 这是push_back做不到的cout << "*********************************" << endl;// 4.对于复杂类型(pair)的测试list<pair<bit::string, int>> lt1;// 4.1 传入左值pairpair<bit::string, int> kv("苹果", 1);lt1.emplace_back(kv);  // 会调用pair的拷贝构造,和push_back效果一样cout << "*********************************" << endl;// 4.2 传入右值pairlt1.emplace_back(move(kv));  // 会调用pair的移动构造,和push_back效果一样cout << "*********************************" << endl;// 4.3 直接传入构造pair需要的参数lt1.emplace_back("苹果", 1);  // 直接在list节点空间构造pair对象// 避免了先构造临时pair再拷贝/移动的过程// 这是push_back做不到的cout << "*********************************" << endl;return 0;
}

list实现empalce

List.h

namespace bit
{// 链表节点结构template<class T>struct ListNode{ListNode<T>* _next;ListNode<T>* _prev;T _data;// 移动构造版本的节点构造函数ListNode(T&& data):_next(nullptr), _prev(nullptr), _data(move(data))  // 使用移动语义构造数据{}// 完美转发构造函数,支持任意参数包构造数据成员template <class... Args>ListNode(Args&&... args): _next(nullptr), _prev(nullptr), _data(std::forward<Args>(args)...)  // 完美转发参数包到数据成员的构造函数{}};// 迭代器类,支持不同类型的引用和指针template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;Node* _node;ListIterator(Node* node):_node(node){}// 前置++运算符重载Self& operator++(){_node = _node->_next;return *this;}// 前置--运算符重载Self& operator--(){_node = _node->_prev;return *this;}// 解引用运算符重载Ref operator*(){return _node->_data;}// 不等运算符重载bool operator!=(const Self& it){return _node != it._node;}};// list类的实现template<class T>class list{typedef ListNode<T> Node;public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;// 返回指向第一个节点的迭代器iterator begin(){return iterator(_head->_next);}// 返回指向哨兵节点的迭代器iterator end(){return iterator(_head);}// 初始化空链表(创建哨兵节点)void empty_init(){_head = new Node();  // 创建哨兵节点_head->_next = _head;  // 首尾相连_head->_prev = _head;}// 默认构造函数list(){empty_init();}// 尾插左值void push_back(const T& x){insert(end(), x);}// 尾插右值void push_back(T&& x){insert(end(), move(x));}// 在指定位置插入左值iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* newnode = new Node(x);Node* prev = cur->_prev;// 连接节点prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}// 在指定位置插入右值iterator insert(iterator pos, T&& x){Node* cur = pos._node;Node* newnode = new Node(move(x));Node* prev = cur->_prev;// 连接节点prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}// emplace_back的可变参数模板版本template <class... Args>void emplace_back(Args&&... args){insert(end(), std::forward<Args>(args)...);}// 在指定位置直接构造插入的可变参数模板版本template <class... Args>iterator insert(iterator pos, Args&&... args){Node* cur = pos._node;// 直接在节点位置构造对象Node* newnode = new Node(std::forward<Args>(args)...);Node* prev = cur->_prev;// 连接节点prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}private:Node* _head;  // 指向哨兵节点的指针};
}

Test.cpp

#include"List.h"int main()
{bit::list<bit::string> lt;// 测试1:传入左值bit::string s1("111111111111");lt.emplace_back(s1);   // 参数是左值,会调用拷贝构造// 这种情况下emplace_back和push_back性能一样cout << "*********************************" << endl;// 测试2:传入右值lt.emplace_back(move(s1));  // 参数是右值,会调用移动构造// 这种情况下emplace_back和push_back性能一样cout << "*********************************" << endl;// 测试3:直接传入构造string需要的参数lt.emplace_back("111111111111");  // 直接在节点空间构造string对象// 避免了先构造临时string对象,再拷贝/移动的过程// 这是push_back做不到的,更高效cout << "*********************************" << endl;// 测试4:对复杂类型pair的操作bit::list<pair<bit::string, int>> lt1;// 测试4.1:传入左值pairpair<bit::string, int> kv("苹果", 1);lt1.emplace_back(kv);  // 会调用pair的拷贝构造// 和push_back效果一样cout << "*********************************" << endl;// 测试4.2:传入右值pairlt1.emplace_back(move(kv));  // 会调用pair的移动构造// 和push_back效果一样cout << "*********************************" << endl;// 测试4.3:直接传入构造pair需要的参数lt1.emplace_back("苹果", 1);  // 直接在节点空间构造pair对象// 避免了先构造临时pair再拷贝/移动// 这是push_back做不到的,更高效cout << "*********************************" << endl;return 0;
}

文章转载自:

http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://00000000.gchqy.cn
http://www.dtcms.com/wzjs/617409.html

相关文章:

  • 做公司网站需要服务器吗财务公司网站建设
  • 有经验的武进网站建设中山建设公司网站
  • 戴尔网站建设成功的关键网站建设后预期推广方式
  • vps上的网站运行太慢深圳建网站一般多少钱
  • 岷县城乡建设局网站网络营销推广seo
  • 邢台信息发布平台seo模拟点击工具
  • 中学生怎么做网站ppt排版布局
  • 企业集团网站建设方案论文无锡免费做网站
  • 网络公司网站模板微网站可以做商城吗
  • 导航网站头部代码南京计算机培训机构哪个最好
  • 深圳开发的购物网站蓝色大气网站模板
  • 外贸型网站建设方法广州网站开发怎么做
  • wordpress 字段键网站优化和网站推广
  • 珠海建设局网站首页平面设计培训班哪里有
  • 网站二维码代码wordpress网址
  • 郑州门户网站建设哪家好wordpress网易音乐播放器
  • 高毅资产网站谁做的商城网站建设的优点
  • 新网站做seo太原建站一条龙
  • 建立企业网站选什么好建设部网站注册中心
  • 济南seo整站优化招商电话开发一个网站成本
  • 相册模版网站图片展示国产4k高清电视十大排名
  • 网站模板后台百度seo刷排名网址
  • 怎么把文件发送到网站做网站交互
  • 响应式网站模板 食品wordpress获取文章内容页的分类
  • php开发网站的优势高端的佛山网站建设价格
  • 临淄网站建设yx718分类信息有哪些网站
  • 做微信商城网站哪家好wordpress 如何迁移
  • 网站建设哪个好网站优化的内容
  • 网站建设-应酷天元建设集团有限公司一公司尤作岭
  • 新农村建设的网站大连做网站哪里好