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

带娃儿做的工作网站中企动力是做什么的公司

带娃儿做的工作网站,中企动力是做什么的公司,大型网站建设价格多少,xampp使用教程 wordpress目录 前言#xff1a;一、创建文件和类二、实现string类2.1 私有成员和构造函数2.2 析构函数2.3 拷贝构造函数2.3.1 写法12.3.2 写法2 2.4 赋值重载函数2.4.1 写法12.4.2 写法2 2.5 迭代器遍历访问2.6 下标遍历访问2.7 reserve2.8 resize2.9 判空和清理2.10 尾插2.10.1 尾插字… 目录 前言一、创建文件和类二、实现string类2.1 私有成员和构造函数2.2 析构函数2.3 拷贝构造函数2.3.1 写法12.3.2 写法2 2.4 赋值重载函数2.4.1 写法12.4.2 写法2 2.5 迭代器遍历访问2.6 下标遍历访问2.7 reserve2.8 resize2.9 判空和清理2.10 尾插2.10.1 尾插字符2.10.2 尾插字符串 2.11 运算符重载2.12 插入2.12.1 插入字符2.12.2 插入字符串 2.13 删除2.14 查找2.15 截取子串2.16 关系运算符重载2.17 和 三、全部代码3.1 string.h3.2 test.cpp 前言 前面已经学习了string类的用法这篇文章将更深入的学习string类了解string类的底层是怎么实现的。当然这里只是模拟一些常用的不常用的可以看文档学习。 一、创建文件和类 我们一共创建两个文件一个是test.cpp文件用于测试另一个是string.h文件用于声明和定义要模拟的string类。模拟的string类会与C标准库里的string类冲突所以这里可以使用命名空间来解决这个问题。 namespace yss {class string{public:private:}; }我们要模拟的string类在yss这个命名空间里所以等会使用这个string类就去yss里找。 注声明和定义都在头文件里写 二、实现string类 2.1 私有成员和构造函数 私有成员变量主要有 _str——字符数组 _size——字符有效个数 _capacity——数组总空间大小总空间大小体现在数组开辟的空间大小 npos——静态成员常量无符号整型的最大值 private:size_t _size;size_t _capacity;char* _str;const static size_t npos -1;为什么声明顺序不是先字符串这个等会再讨论先来看下构造函数 string(const char* str ){_size strlen(str);_capacity _size;_str new char[_capacity 1];strcpy(_str, str);}这里我们定义_capacity 与_size 相同方便后续开辟空间。_size 可以用strlen计算字符串个数为什么_capacity 不用因为再使用一个strlen又要遍历一遍字符串加大了时间复杂度。 注意strlen计算字符串长度不包括斜杠0 前面因为总空间大小和有效字符个数一样又因为字符串末尾要有斜杠0所以实际开辟的字符数组的空间大小比_capacity 多一个位置用于放斜杠0_str 字符数组的空间开辟好后就把参数字符串拷贝过来即可。 注意strcpy会连同斜杠0一起拷贝 如果参数为空字符串该咋办可以给缺省值但是不能为斜杠0因为斜杠0是字符类型而我们这里的形参是字符串类型虽然可以发生类型转换但毕竟不好nullptr指针呢也不行因为如果我们没有传参那么它就是空指针最后要打印对空指针解引用不就报错了吗。所以这里给个空字符串即可。 回到前面的声明私有成员变量的问题我们知道声明的顺序就是初始化列表的顺序但是前面的代码没有用到初始化列表。其实前面的代码只是一种写法构造函数也可以使用初始化列表或者初始化列表与函数体混着使用如果用初始化列表就得注意声明顺序了所以为了防止出错声明顺序就与我们在构造函数里成员变量定义的顺序相同。 验证一下前我们还要实现一个返回C格式的函数顺便把返回字符有效个数、交换和返回容量也写下方便后面操作 //C格式返回 const char* c_str() const {return _str; } //返回字符个数 const size_t size() const {return _size; } //返回容量 const size_t capacity() const {return _capacity; } //交换 void swap(string s) {std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity); }运行结果 总结 一缺省值给空字符串 二多开一个位置放斜杠0 2.2 析构函数 析构函数与我们以前的destroy()函数差不多作用是清理空间。要注意下这里使用的是与new[] 匹配的delete[] 不能把中括号漏了。 ~string() {delete[] _str;_str nullptr;_size 0;_capacity 0; }2.3 拷贝构造函数 2.3.1 写法1 之前的文章提过我们不写编译器会默认生成它的拷贝构造但这是浅拷贝对于非指针变量没有太大关系但如果是指针成员变量导致两个指针指向同一块空间会有一块内存重复释放的风险所以要用深拷贝额外开一块空间自己来实现。 先上代码 string(const string s) {_str new char[s._capacity 1];strcpy(_str, s._str);_size s._size;_capacity s._capacity; }深拷贝意味着要临时多开一块空间这里多开的一块空间就是_str的因为_str是刚被初始化的对象的字符串所以给它开辟空间方式与前面的构造函数相同_size 与_capacity 值拷贝。 str指的是s._str 运行结果 2.3.2 写法2 这个写法更简化 string(const string s){string tmp(s._str);swap(tmp);}也要额外开辟一块空间定义一个string类型的变量tmp构造的内容与要拷贝的内容相同然后将s2的内容与tmp交换就行了。 图示 s2就是用s1拷贝构造出来的对象 因为tmp是局部变量出函数作用域要被销毁掉拷贝构造结束调用析构清理tmp。交换后tmp指向空释放空指针不进行任何操作 2.4 赋值重载函数 2.4.1 写法1 赋值重载类似拷贝构造也要有一个额外空间。 代码 string operator(const string s) {if (this ! s){char* tmp new char[s._capacity 1];strcpy(tmp, s._str);delete[] _str;_str tmp;_size s._size;_capacity s._capacity;}return *this; }返回值是string可以减少拷贝效率高开始的 if 语句是为了判断this指针与要赋值的对象是否相同函数参数列表里的取地址符是引用if 判断里的是取地址如果相同就没必要赋值了因为是自己赋值自己。如果不同才可以进行赋值。 创建一个临时的空间把要赋值的内容拷贝到临时空间里然后把this指针指向的原来的空间销毁掉this指针不显示写还有this指针的字符串原来是有自己的一块空间的然后指向这块临时的空间其他成员变量值拷贝。最后返回this指针。 图 运行结果 2.4.2 写法2 赋值重载的另一个写法也很简洁 string operator(string s) {swap(s);return *this; }形参s没有引用说明它是实参的一份拷贝独立占一块空间正因为独立占一块空间所以它就可以作为this指针的_str交换的临时对象。 如果传的是引用形参s与原来的被赋值的对象共用一块空间交换的话不就把被赋值的对象的内容改变了吗 好了既然如此那么不加引用可是为什么不加const了呢注意不是什么情况都能加const。如果这里加上const那么s就不可以改变了交换就是改变s会报错。 注意一下拷贝构造函数的参数列表里也可以不加const但是某些情况就必须加const这“某些情况”后面会提到。此时这里加不加const都没关系但为了保险起见一般带上const较好 2.5 迭代器遍历访问 有两种写法先来看第一种没有const的 typedef char* iterator; iterator begin() {return _str; } iterator end() {return _str _size; }iterator是迭代器我们以重命名的方式让它成为字符指针的别名。begin返回的是指向首元素地址的指针end返回的是指向斜杠0的指针。 遍历方式是定义一个指针刚开始指向字符串首元素的位置然后循环不等于斜杠0就打印直到遇到斜杠0跳出。 yss::string s1(hello world);yss::string::iterator it s1.begin();while (it ! s1.end()){cout *it;it;}cout endl;运行结果 有const的写法 typedef const char* const_iterator; const_iterator begin() const {return _str; } const_iterator end() const {return _str _size; }用法是上面的一样只不过不可以修改值只能打印。 2.6 下标遍历访问 也有const和非const的写法使用方式就是常见的下标遍历 char operator[](size_t pos){assert(pos _size);return _str[pos];}const char operator[](size_t pos) const{assert(pos _size);return _str[pos];}使用assert可以预防pos下标越界的问题 2.7 reserve 如果要插入字符或字符串当字符数组的空间大小不满足需求时就要进行扩容。模拟实现的函数是reserve。 reserve 1.不改变有效字符个数不影响字符串内容只影响空间大小 2.当参数大于空间总大小时空间总大小增加小于等于时不变 3.不会缩容 代码 void reserve(size_t n) {if (n _capacity){char* tmp new char[n 1];strcpy(tmp, _str);delete[] _str;_str tmp;_capacity n;} }扩容的也需要开辟一块临时空间tmptmp的实际空间大小为n1多一个放斜杠0将_str的内容拷贝到tmp临时空间里然后销毁掉原来的空间指向新的空间原来的空间大小_capacity扩到n完成扩容。 2.8 resize resize可以改变字符串的有效字符个数当传入的参数n小于原来有效字符个数时有效字符个数为n同时字符串的内容也发生改变如果大于在原来字符串的末尾填充字符填充的个数为参数减去原来的有效字符个数。 void resize(size_t n, char ch) {if (n _size){_str[n] \0;}else{if (n _capacity){reserve(n);}for (size_t i _size; i n; i){_str[i] ch;}_str[n] \0;}_size n; }n小于等于_size就在下标为n的位置改为斜杠0等于_size就是原来斜杠0的位置放斜杠0。n大于有效字符个数的情况如果n大于空间大小就要扩容只要大于不管有没有扩容都要在末尾逐个插入字符然后在下标为n处放置斜杠0这里不用担心越界问题有或者没有扩容实际字符数组都有多一个位置来处理这个斜杠0。最后有效字符个数要改为n。 运行结果 2.9 判空和清理 如果有效字符个数为0返回真否则假打印结果真为1假为0。清理的是有效字符个数对空间大小没有影响 // 判空 bool empty() {return _size 0; } // 清理 void clear() {_size 0;_str[0] \0; }注意清理函数里如果字符串的首元素不改为斜杠0清理完后再打印它依然可以打印出这个字符串因为返回C格式字符串是有带斜杠0返回的也就是说正常情况下打印这个字符串到它的斜杠0位置结束所以这里的意思是函数里如果字符串的首元素不改为斜杠0在实际的空间里这个字符串于原来没被清理的状态一样只是有效字符个数_size改变了而已。在字符串的首元素改为斜杠0那么打印时遇到斜杠0停下即什么都没有打印出来这个字符串就与被清理的效果一样了。 2.10 尾插 2.10.1 尾插字符 尾插字符要注意空间是否够用不够要扩容 代码 void push_back(char ch) {if (_size _capacity){size_t newcapacity _capacity 0 ? 4 : 2 * _capacity;reserve(newcapacity);}_str[_size] ch;_size;_str[_size] \0; }当_size等于_capacity就要扩容扩到原来_capacity的两倍大小然后尾插字符有效字符个数加1再最后放斜杠0 运行结果 2.10.2 尾插字符串 先要计算要插入的字符串的字符个数如果原来字符串的有效个数加上插入的字符串的字符个数大于空间大小就要扩容。然后进行尾插有效字符个数为相加的结果。 void append(const char* str) {size_t len strlen(str);if (_size len _capacity){reserve(_size len);}strcpy(_str _size, str);_size len; }为什么这里是_size len _capacity而不是 假设原来的字符串的_size8_capacity9新插入的字符串就一个字符。此时_capacity还有一个位置刚好可以放这一个字符所以这种情况就没必要扩容。还有一种情况是要插入的字符串为空串那么最后得到的还是自己原来的字符串就算原来的字符串_size _capacity也不需要扩容因为此时又没有要插入的东西。或者说插入空串相当于啥也没插入 2.11 运算符重载 运算符可以实现两种尾插方式既可以尾插字符也可以尾插字符串 string operator(char ch) {push_back(ch);return *this; } string operator(const char* str) {append(str);return *this; }复用前面的函数然后返回this指针 2.12 插入 2.12.1 插入字符 插入操作都要考虑是否要扩容扩容与前面尾插字符一样。插入的位置可能是头也可能是中间所以要挪动数据。 void insert(char ch, size_t pos) {assert(pos _size);//插入要考虑是否要扩容if (_size _capacity){size_t newcapacity _capacity 0 ? 4 : 2 * _capacity;reserve(newcapacity);}//挪动数据int end _size;while (end (int)pos)//强转类型{_str[end 1] _str[end];--end;}_str[pos] ch;_size; }运行结果 2.12.2 插入字符串 主要这几点考虑是否扩容挪动数据拷贝字符串 代码 void insert(const char* str, size_t pos) {assert(pos _size);size_t len strlen(str);//考虑是否扩容if (_size len _capacity){reserve(_size len);}//挪动数据int end _size;while (end (int)pos){_str[end len] _str[end];--end;}strncpy(_str pos, str, len);_size; }这里的拷贝字符串就跟前面的不一样了strncpy会把要插入的字符串拷贝到中间空出来的位置去并且会控制个数即在中间某个位置插入一个字符串这个位置之后原来的字符串没有被覆盖掉如果是用strcpy那么插入的位置之后原来的字符串就都被要插入的字符串覆盖。 运行结果 2.13 删除 如果要删除的个数len是默认的缺省值从pos位置开始后面全部删除或者pos的值加上len大于等于字符个数也是从pos位置开始后面全部删除pos位置就放斜杠0有效字符个数变为pos的值。从pos开始后面不全删就把pos位置加len后的字符串覆盖到pos位置之后_size减去len。 代码 void erase(size_t pos, size_t len npos) {assert(pos _size);// 从pos开始后面都删除if (len npos || pos len _size){_str[pos] \0;_size pos;}//从pos开始后面不全删else{strcpy(_str pos, _str pos len);_size - len;} }运行结果 2.14 查找 查找字符/字符串 从左往右查找字符找到了返回该字符的下标否则返回npos size_t find(char ch, size_t pos 0) {assert(pos _size);for (size_t i 0; i _size; i){if (ch _str[i]){return i;}}return npos; }从左往右查找字符串使用字符串函数strstr定义一个变量得到字符串函数的返回结果这个返回结果如果是空说明没找到就返回npos否则返回该指针的下标即找到字符串的第一个字符下标。 size_t find(const char* str, size_t pos 0) {assert(pos _size);char* ptr strstr(_str, str);if (ptr nullptr){return npos;}else{return ptr - _str;} }运行结果 2.15 截取子串 代码 string substr(size_t pos 0, size_t len npos) {assert(pos _size);size_t end pos len;if (len npos || pos len _size){end _size;}string ss;ss.reserve(end - pos);for (size_t i pos; i end; i){ss _str[i];}return ss; }先定义一个变量end确定截取的字符串在源字符串的最后位置假设poslen的值就是end指向的下标处。如果len是缺省值或者pos加上要len大于_sizeend就等于_size不满足条件就是假设的值。定义一个对象使其尾插原字符串从pos位置到end位置的字符最后返回的就是截取的字符串。 运行一下 这里就可以解决前面的一个问题了拷贝构造函数的第二种写法某些情况必须加const 刚刚写的截取字符串是传值返回返回的是返回值的临时拷贝这个临时对象具有常属性用其他对象接收时要带上const 图示 可能有人会想这里为什么要用引用接收不用引用行不行答案是绝对不行因为没有引用拷贝构造会无限递归一直循环调用。 2.16 关系运算符重载 代码 //大于bool operator(string s) const{return strcmp(_str, s._str) 0;}//等于bool operator(string s) const{return strcmp(_str, s._str) 0;}//大于等于bool operator(string s) const{return (*this s *this s);}//小于bool operator(string s) const{return !(*this s);}//小于等于bool operator(string s) const{return !(*this s);}//不等于bool operator!(string s) const{return !(*this s);}2.17 和 之前我们写输出的函数要用友元函数现在有个方法可以不用友元 ostream operator(ostream out, const string s){for (auto e : s){out e;}return out;}范围for直接打印对象里面的字符。 输入的函数也不需要友元 istream operator(istream in, string s) {char ch;in ch;while (ch ! \n ch ! ){s ch;in ch;}return in; }运行一下 结果发现好像停不下来了因为cin和scanf一样读取时对空格或者换行会进行忽略所以一直在循环里 解决方法使用cin的get函数可以读取到空格或者换行 istream operator(istream in, string s){s.clear();//清理之前的字符串char ch in.get();while (ch ! \n ch ! ){ s ch;ch in.get();}return in;}三、全部代码 3.1 string.h #include iostream #include assert.h #includestring.h using namespace std;namespace yss {class string{public://迭代器遍历typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str _size;}//构造string(const char* str ){_size strlen(str);_capacity _size;_str new char[_capacity 1];strcpy(_str, str);}//析构~string(){delete[] _str;_str nullptr;_size 0;_capacity 0;}//C格式返回const char* c_str() const{return _str;}//返回字符个数const size_t size() const{return _size;}//返回容量const size_t capacity() const{return _capacity;}//交换void swap(string s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}//拷贝构造/*string(const string s){_str new char[s._capacity 1];strcpy(_str, s._str);_size s._size;_capacity s._capacity;}*/string(const string s){string tmp(s._str);swap(tmp);}//赋值重载/*string operator(const string s){if (this ! s){char* tmp new char[s._capacity 1];strcpy(tmp, s._str);delete[] _str;_str tmp;_size s._size;_capacity s._capacity;}return *this;}*/string operator(string s){swap(s);return *this;}//下标遍历访问char operator[](size_t pos){assert(pos _size);return _str[pos];}const char operator[](size_t pos) const{assert(pos _size);return _str[pos];}//扩容void reserve(size_t n){if (n _capacity){char* tmp new char[n 1];strcpy(tmp, _str);delete[] _str;_str tmp;_capacity n;}}//修改有效字符void resize(size_t n, char ch){if (n _size){_str[n] \0;}else{if (n _capacity){reserve(n);}for (size_t i _size; i n; i){_str[i] ch;}_str[n] \0;}_size n;}// 判空bool empty(){return _size 0;}// 清理void clear(){_size 0;_str[0] \0;}//尾插字符void push_back(char ch){if (_size _capacity){size_t newcapacity _capacity 0 ? 4 : 2 * _capacity;reserve(newcapacity);}_str[_size] ch;_size;_str[_size] \0;}//尾插字符串void append(const char* str){size_t len strlen(str);if (_size len _capacity){reserve(_size len);}strcpy(_str _size, str);_size len;}// string operator(char ch){push_back(ch);return *this;}string operator(const char* str){append(str);return *this;}//插入void insert(char ch, size_t pos){assert(pos _size);//插入要考虑是否要扩容if (_size _capacity){size_t newcapacity _capacity 0 ? 4 : 2 * _capacity;reserve(newcapacity);}//挪动数据int end _size;while (end (int)pos){_str[end 1] _str[end];--end;}_str[pos] ch;_size;}void insert(const char* str, size_t pos){assert(pos _size);size_t len strlen(str);//考虑是否扩容if (_size len _capacity){reserve(_size len);}//挪动数据int end _size;while (end (int)pos){_str[end len] _str[end];--end;}strncpy(_str pos, str, len);_size;}//删除void erase(size_t pos, size_t len npos){assert(pos _size);// 从pos开始后面都删除if (len npos || pos len _size){_str[pos] \0;_size pos;}//从pos开始后面不全删else{strcpy(_str pos, _str pos len);_size - len;}}//查找字符size_t find(char ch, size_t pos 0){assert(pos _size);for (size_t i 0; i _size; i){if (ch _str[i]){return i;}}return npos;}//查找字符串size_t find(const char* str, size_t pos 0){assert(pos _size);char* ptr strstr(_str, str);if (ptr nullptr){return npos;}else{return ptr - _str;}}//截取子串string substr(size_t pos 0, size_t len npos){assert(pos _size);size_t end pos len;if (len npos || pos len _size){end _size;}string ss;ss.reserve(end - pos);for (size_t i pos; i end; i){ss _str[i];}return ss;}//大于bool operator(string s) const{return strcmp(_str, s._str) 0;}//等于bool operator(string s) const{return strcmp(_str, s._str) 0;}//大于等于bool operator(string s) const{return (*this s *this s);}//小于bool operator(string s) const{return !(*this s);}//小于等于bool operator(string s) const{return !(*this s);}//不等于bool operator!(string s) const{return !(*this s);}private:size_t _size;size_t _capacity;char* _str;const static size_t npos -1;};// ostream operator(ostream out, const string s){for (auto e : s){out e;}return out;}// /*istream operator(istream in, string s){char ch;in ch;while (ch ! \n ch ! ){s ch;in ch;}return in;}*/istream operator(istream in, string s){s.clear();char ch in.get();while (ch ! \n ch ! ){s ch;ch in.get();}return in;} }3.2 test.cpp #include string.hint main() {/*yss::string s1(hello yss);cout s1.c_str() endl;*//*yss::string s1(hello yss);yss::string s2(s1);cout s2.c_str() endl;*//*yss::string s1(hello yss);yss::string s2 s1;cout s2.c_str() endl;*///yss::string s1(hello world);//yss::string::iterator it s1.begin();//while (it ! s1.end())//{// cout *it;// it;//}//cout endl;/*yss::string s1(hello world);yss::string::const_iterator it s1.begin();while (it ! s1.end()){cout *it;it;}cout endl;*//*yss::string s1(hello world);for (size_t i 0; i s1.size(); i){cout s1[i] ;}cout endl;*//*yss::string s1(hello yss);cout s1.c_str() endl;cout s1.size() endl;cout s1.capacity() endl;s1.resize(12,q);cout s1.c_str() endl;cout s1.size() endl;cout s1.capacity() endl;*//*yss::string s1(hello yss);cout s1.empty() endl;cout s1.size() endl;cout s1.c_str() endl;cout s1.capacity() endl;s1.clear();cout s1.empty() endl;cout s1.size() endl;cout s1.c_str() endl;cout s1.capacity() endl;*//*yss::string s1(hello yss);s1.push_back(a);cout s1.c_str() endl;*//*yss::string s1(hello yss);s1.append(abcd);cout s1.c_str() endl;*//*yss::string s1(hello yss);s1 a;cout s1.c_str() endl;yss::string s2(hello yss);s2 abcd;cout s2.c_str() endl;*//*yss::string s1(hello yss);s1.insert(a, 3);cout s1.c_str() endl;*//*yss::string s1(hello yss);s1.insert(abcd, 3);cout s1.c_str() endl;*//*yss::string s1(hello yss);s1.erase(3);cout s1.c_str() endl;yss::string s2(hello);s2.erase(2, 2);cout s2.c_str() endl;*//*yss::string s1(hello yss);size_t p s1.find(o);cout p endl;p s1.find(ss);cout p endl;*//*yss::string s1(hello yss);yss::string s2 s1.substr(1, 7);cout s2.c_str() endl;*//*yss::string s1(hello yss);cout s1 endl;*//*yss::string s1;cin s1;cout s1 endl;*//*yss::string s1(hello);cout s1 endl;cin s1;cout s1 endl;*/yss::string s1(hello);yss::string s2(aabbc);cout (s1 s2) endl;cout (s1 s2) endl;cout (s1 s2) endl;cout (s1 s2) endl;cout (s1 s2) endl;cout (s1 ! s2) endl;return 0; }
http://www.pierceye.com/news/581566/

相关文章:

  • 上海网站建设公司服务沅江网站制作
  • 公司网站开发费用计入什么科目虚拟主机怎么建网站
  • 天津网站建设技术网页设计与制作教程版徐洪亮课后答案
  • 旅游网站建设方案简介用asp做的网站打开页面很慢
  • 做影视网站 片源从哪里来做自媒体的上那些网站
  • 邢台网站开发百度云 做网站
  • 淘宝优惠劵网站建设wordpress主题 简洁
  • 自己做电影资源网站揭阳新闻最新消息
  • 北碚免费建站哪家做得好佛山网站建设设计
  • 怎么做网站拍卖的那种wordpress主题搜索图标
  • 三亚网站建设平台查数据的权威网站
  • html网站制作答辩ppt网站备份和备案的区别
  • 网站开发需要工具免费的ps软件
  • 常州网站建设优质商家重庆互联网怎么样
  • 做网站发广告动漫网页设计报告
  • 求职招聘网站建设投标书沈阳网站建设的公司哪家好
  • 做导航网站有发展吗南京企业网站制作哪家好
  • 千万pv网站开发成本招聘网站数建设
  • 吐鲁番大型网站建设平台找客户去哪个平台
  • 权威网站有哪些给个网站可以在线
  • 优化网站专题北京海淀网站建设公司
  • 广州网站快速排名网站维护正常要多久
  • 建网站 选安全甘肃做网站价格
  • 微信公众管理平台有必要买优化大师会员吗
  • 家居网站建设素材腾讯adq广告平台
  • 响应式网站 图片居中门户网站样式
  • 潍坊网站排名推广北京建设高端网站的
  • 广东省住房和建设网站鹤壁市建设局网站
  • 北京网站建设报价明细手机网站网站开发流程
  • 三合一网站模板如何看网站是html几代做的