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

一般纳税人网站建设多少税率沈阳做平板网站

一般纳税人网站建设多少税率,沈阳做平板网站,wordpress采集英文,彩票投资理财平台网站建设模拟实现string类不是为了造一个更好的轮子#xff0c;而是更加理解string类#xff0c;从而来掌握string类的使用 string类的接口设计繁多#xff0c;故而不会全部涵盖到#xff0c;但是核心的会模拟实现 库中string类是封装在std的命名空间中的#xff0c;所以在模拟…模拟实现string类不是为了造一个更好的轮子而是更加理解string类从而来掌握string类的使用 string类的接口设计繁多故而不会全部涵盖到但是核心的会模拟实现  库中string类是封装在std的命名空间中的所以在模拟实现中我们也可以用命名空间来封装 string类的实现可以在.h头文件中.cpp文件中再来实际操作string类对象 完整的代码实现 namespace djx {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(const string s){_str new char[s._capacity 1];strcpy(_str, s._str);_size s._size;_capacity s._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(nullptr),_size(0),_capacity(0){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;}*///现代写法1/*string operator(const string s){if (this ! s){string tmp(s);swap(tmp);}return *this;}*///现代写法2string operator(string s){swap(s);return *this;}~string(){delete[] _str;_str nullptr;_size _capacity 0;}const char* c_str()const{return _str;}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 push_back(char ch){if (_size _capacity){reserve(_capacity 0 ? 4 : _capacity * 2);}_str[_size] ch;_size;_str[_size] \0;}void append(const char* s){size_t len strlen(s);if (_size len _capacity){reserve(_size len);}strcpy(_str_size, s);_size len;}string operator(char ch){push_back(ch);return *this;}string operator(const char* s){append(s);return *this;}/*void insert(size_t pos, char ch){assert(pos _size);if (_size _capacity){reserve(_capacity 0 ? 4 : _capacity * 2);}int end _size;while (end (int) pos){_str[end 1] _str[end];end--;}_str[pos] ch;_size;}*/void insert(size_t pos, char ch){assert(pos _size);if (_size _capacity){reserve(_capacity 0 ? 4 : _capacity * 2);}size_t end _size1;while (end pos){_str[end] _str[end-1];end--;}_str[pos] ch;_size;}void insert(size_t pos, const char* s){assert(pos _size);size_t len strlen(s);if (_size len _capacity){reserve(_size len);}int end _size;while (end (int) pos){_str[end len] _str[end];end--;}strncpy(_str pos, s, len);_size len;}void erase(size_t pos, size_t len npos){assert(pos _size);if (len npos || pos len _size){_str[pos] \0;_size pos;}else{size_t begin pos len;while (begin _size){_str[begin - len] _str[begin];begin;}_size - len;}}bool operator(const string s)const{return strcmp(_str, s._str) 0;}bool operator(const string s)const{return strcmp(_str, s._str) 0;}bool operator(const string s)const{return *this s || *this s;}bool operator(const string s)const{return !(*this s);}bool operator(const string s)const{return !(*this s);}bool operator!(const string s)const{return !(*this s);}void resize(size_t n,char ch\0){if (n _size){_str[n] \0;_size n;}else{reserve(n);while (_size n){_str[_size] ch;_size;}_str[_size] \0;}}size_t find(char ch, size_t pos 0){for (size_t i pos; i _size; i){if (_str[i] ch){return i;}}return npos;//没有找到}size_t find(const char* s, size_t pos0){const char* p strstr(_strpos, s);if (p){return p - _str;}else{return npos;}}string substr(size_t pos, size_t len npos){string s;size_t end pos len;if (len npos || pos len _size){len _size - pos;end _size;}s.reserve(len);for (size_t i pos; i end; i){s _str[i];}return s;}size_t size()const{return _size;}size_t capacity()const{return _capacity;}void clear(){_str[0] \0;_size 0;}private:char* _str;size_t _size;size_t _capacity;public:const static size_t npos;//const static size_t npos-1;//特例//const static double npos 1.1; // 不支持};const size_t string::npos -1;ostream operator(ostream out, const string s){for (auto e : s){out e;}return out;}istream operator(istream in, string s){s.clear();char buff[129];size_t i 0;char ch;ch in.get();while (ch ! ch ! \n){buff[i] ch;if (i 128){buff[i] \0;s buff;i 0;}ch in.get();}if (i ! 0){buff[i] \0;s buff;}return in;} }构造函数和析构函数 namespace djx {class string{public:string(const char* str )//构造函数:_size(strlen(str))//在对象中的成员都要走初始化列表成员们定义的地方,_capacity(_size){_str new char[_capacity 1];//多开一个空间给\0strcpy(_str, str);}~string()//析构函数{delete[] _str;//释放空间调用对象的析构函数用于清理申请的资源_str nullptr;_size _capacity 0;}const char* c_str()const//返回c格式的字符串,加const用以修饰this指针让const对象可以调用非const对象也是可以调用的{return _str;}private:char* _str;//指向存储字符串的空间size_t _size;//有效字符的个数size_t _capacity;//存储有效字符的容量}; } 测试 string类的对象可以重载流插入流提取运算符但现在我们还没有实现又想查看string类中字符串的内容可以用c_str 得到_str void test1() {djx::string s(hello);cout s.c_str() endl;djx::string s2;cout s2.c_str() endl; } 构造函数 1 库中string实现对于无参的string初始化为空字符串对于有参的string则初始化为参数内容 所以可以给构造函数缺省参数缺省值是注意不能是 因为空格也是有效字符也没必要是\0因为常量字符串自动会带有一个\0 2 _size 和_capacity是不算\0的大小的它只是一个标识字符因为c语言需要\0作为字符串的结束标志c不能抛弃c所以\0被保留下来了 实际在开空间时也是需要为\0预留一个空间的 string的三种遍历方式 operator[]重载 #includeassert.h namespace djx {class string{public:string(const char* str ):_size(strlen(str)),_capacity(_size){_str new char[_capacity 1];strcpy(_str, str);}~string(){delete[] _str;_str nullptr;_size _capacity 0;}const char* c_str()const{return _str;}char operator[](size_t pos)//非const对象调用返回引用可读可写{assert(pos _size);return _str[pos];}const char operator[](size_t pos)const//const对象调用只读不可写{assert(pos _size);return _str[pos];}size_t size()const//const对象可以调用非const对象也可以调用{return _size;}size_t capacity()const{return _capacity;}private:char* _str;size_t _size;size_t _capacity;}; }测试 void test2() {djx::string s(hello);for (size_t i 0; i s.size(); i){cout s[i];}cout endl; } 迭代器 string类的迭代器可以看作是指针因为它完美契合指针的行为 namespace djx {class string{public:typedef char* iterator;//非const对象的迭代器typedef const char* const_iterator;//const对象的迭代器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 _capacity 0;}const char* c_str()const{return _str;}char operator[](size_t pos){assert(pos _size);return _str[pos];}const char operator[](size_t pos)const{assert(pos _size);return _str[pos];}size_t size()const{return _size;}size_t capacity()const{return _capacity;}private:char* _str;size_t _size;size_t _capacity;}; }测试 void test3() {djx::string s(hello);cout s.c_str() endl;djx::string::iterator it s.begin();while (it ! s.end()){(*it);//写cout *it;//读it;}cout endl; } 范围for 范围for的底层原理是迭代器所以有了迭代器就可以使用范围for 测试 void test4() {djx::string s(hello);cout s.c_str() endl;for (auto e : s)//不加引用就是只读{e;//写cout e;//读}cout endl; } 插入和删除操作 push_back: 尾插一个字符插入之前需要检查是否需要扩容扩容扩至原来的2倍 注意_size_capacity 可能是第一次插入双方都是0那么2*_capacity就是0所以如果是第一次插入的扩容可以扩4个空间 扩容可以使用reserve 1 开n个空间实际上reserve要开n1个空间因为要存\0 2 拷贝数据到新空间 3 释放旧空间 4 指向新空间 append 插入之前要检查是否需要扩容原有效字符个数要插入的有效字符个数_capacity则扩容 operator 目前阶段的完整代码 #includeassert.h namespace djx {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 _capacity 0;}const char* c_str()const{return _str;}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 push_back(char ch){if (_size _capacity){reserve(_capacity 0 ? 4 : _capacity * 2);}_str[_size] ch;_size;_str[_size] \0;}void append(const char* s){size_t len strlen(s);if (_size len _capacity){reserve(_size len);}strcpy(_str_size, s);_size len;}string operator(char ch){push_back(ch);return *this;}string operator(const char* s){append(s);return *this;}size_t size()const{return _size;}size_t capacity()const{return _capacity;}private:char* _str;size_t _size;size_t _capacity;}; }测试 void test5() {djx::string s(hello);cout s.c_str() endl;s.push_back( );s.append(world);cout s.c_str() endl;s #;s !!!!!!!!!;cout s.c_str() endl;djx::string s2;s2 #;s2 !!!!!!!!!!;cout s2.c_str() endl; }insert 插入一个字符版本1 在pos位置插入一个字符就需要从\0开始直到pos位置将这些位置上的数据全部向后挪动一位 不要忘记把\0一并移走  注意如果是头插pos0且end是size_t类型那么循环的结束条件是endpos 即end0但由于end是size_t类型是不会0的让end写成int类型那么end可以达到-1为避开隐式类型转换将end由int提升为size_t所以pos也要强制为int类型这样当pos为0时end可以达到-1-10结束循环  版本2 版本1利用强转来解决循环条件的结束问题版本2不强转 将end作为最后一个要挪动的数据的最终位置endpos1的位置时pos位置上的值已经挪到pos1上了当endpos位置时结束循环 插入常量字符串 可以尾插所以pos可以是_size 1 检查原有效字符个数要插入的有效字符格式是否_capacity大于则扩容 2 从\0位置开始一直到pos位置上的数据将它们全部向后挪动len步 3 将常量字符串拷贝到_strpos的位置只要拷贝len个不要使用strcpy全部拷贝因为会拷贝到\0 erase 有两种情况 一从pos位置开始有多少删多少 1 当没有给len传参时len使用缺省值npossize_t类型的-1很大的数字但是一个字符串不会有那么大所以npos通常可以理解为有多少要多少即从pos位置开始全部删除 2  传参给len但若poslen_size (poslen是要删除的最后一个数据的下一个位置也是从pos位置开始全部删除 方法在pos位置给\0 二从pos位置开始删除len个字符  poslen是合法的那么从poslen位置开始一直到\0要将它们全部向前移动len步覆盖效果 不要忘记移动\0 len给一个缺省值nposconst修饰的静态变量值为-1 静态成员变量不在对象中不走初始化列表在类外定义给初始值-1 但是 const修饰的静态整型成员变量是一个特例可以在声明的地方给缺省值 其实在常规情况下成员变量声明的地方给缺省值就代表它们在走初始化列表的时候可以被初始化 流插入和流提取重载 流插入 ostream operator(ostream out, const string s){for (auto e : s){out e;}return out;} 会有coutss2的情况所以有ostream类型的返回值 out出了作用域还在所以可以用传引用返回提高效率 流提取 void clear(){_str[0] \0;_size 0;} istream operator(istream in, string s){s.clear();//在向string类的对象输入内容时要情况原有的所有数据char buff[129];size_t i 0;char ch;ch in.get();while (ch ! ch ! \n){buff[i] ch;if (i 128){buff[i] \0;s buff;i 0;//从头再来}ch in.get();}if (i ! 0)//可能字符串的长度没有达到128个{buff[i] \0;s buff;}return in;} 会有cinss2的情况所以有istream类型的返回值 在输入的字符串很长的情况下若是提取一个字符便到string类的对象中难免会有多次扩容 若以为了提高效率可以开一个能存储129个字符的buff数组提取的字符先存储到buff数组中 当有了128个字符时加入\0再将buff数组中的所有字符以字符串的形式一并到string类的对象中  buff数组就像一个蓄水池水满了就全部拿走然后再接着蓄水满了再全部拿走 注意cin和scanf一样不能提取到空格或者\nscanf中用getchar可以提取任意字符那在cin中有get可以提取任意字符 测试 void test6() {djx::string s(hello world);cout s.c_str() endl;//没有重载流插入运算符之前打印string类对象的内容s.insert(5, %);cout s.c_str() endl;s.insert(s.size(), %);cout s.c_str() endl;s.insert(0, %);cout s.c_str() endl;djx::string s2(hello world);s2.insert(5, abc);cout s2 endl;//重载流插入运算符之后打印string类对象的内容s2.insert(0, xxx);cout s2 endl;s2.erase(0, 3);cout s2 endl;s2.erase(5, 100);cout s2 endl;s2.erase(2);cout s2 endl;} void test7() {djx::string s(hello world);cout s endl;cin s;cout s endl; } 目前为止的完整代码 #includeassert.h namespace djx {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 _capacity 0;}const char* c_str()const{return _str;}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 push_back(char ch){if (_size _capacity){reserve(_capacity 0 ? 4 : _capacity * 2);}_str[_size] ch;_size;_str[_size] \0;}void append(const char* s){size_t len strlen(s);if (_size len _capacity){reserve(_size len);}strcpy(_str_size, s);_size len;}string operator(char ch){push_back(ch);return *this;}string operator(const char* s){append(s);return *this;}/*void insert(size_t pos, char ch){assert(pos _size);if (_size _capacity){reserve(_capacity 0 ? 4 : _capacity * 2);}int end _size;while (end (int) pos){_str[end 1] _str[end];end--;}_str[pos] ch;_size;}*/void insert(size_t pos, char ch){assert(pos _size);if (_size _capacity){reserve(_capacity 0 ? 4 : _capacity * 2);}size_t end _size1;while (end pos){_str[end] _str[end-1];end--;}_str[pos] ch;_size;}void insert(size_t pos, const char* s){assert(pos _size);size_t len strlen(s);if (_size len _capacity){reserve(_size len);}int end _size;while (end (int) pos){_str[end len] _str[end];end--;}strncpy(_str pos, s, len);_size len;}void erase(size_t pos, size_t len npos){assert(pos _size);if (len npos || pos len _size){_str[pos] \0;_size pos;}else{size_t begin pos len;while (begin _size){_str[begin - len] _str[begin];begin;}_size - len;}}size_t size()const{return _size;}size_t capacity()const{return _capacity;}void clear(){_str[0] \0;_size 0;}private:char* _str;size_t _size;size_t _capacity;public:const static size_t npos;//const static size_t npos-1;//特例//const static double npos 1.1; // 不支持};const size_t string::npos -1;ostream operator(ostream out, const string s){for (auto e : s){out e;}return out;}istream operator(istream in, string s){s.clear();char buff[129];size_t i 0;char ch;ch in.get();while (ch ! ch ! \n){buff[i] ch;if (i 128){buff[i] \0;s buff;i 0;}ch in.get();}if (i ! 0){buff[i] \0;s buff;}return in;} } 关系运算符重载 bool operator(const string s)const{return strcmp(_str, s._str) 0;}bool operator(const string s)const{return strcmp(_str, s._str) 0;}bool operator(const string s)const{return *this s || *this s;}bool operator(const string s)const{return !(*this s);}bool operator(const string s)const{return !(*this s);}bool operator!(const string s)const{return !(*this s);} resize void resize(size_t n,char ch\0){if (n _size)//删除效果{_str[n] \0;_size n;}else//插入效果{reserve(n);while (_size n){_str[_size] ch;_size;}_str[_size] \0;}}ch的缺省值给\0若是没有传参给ch那么就用\0填充  分三种情况 n_size删除效果保留前n个有效字符 _sizen_capacity : 无需扩容直接插入 n_capacity :先扩容再插入 测试 void test8() {djx::string s(hello world);cout s endl;s.resize(5);cout s endl;s.resize(25, x);cout s endl; } find 查找一个字符 size_t find(char ch, size_t pos 0){for (size_t i pos; i _size; i){if (_str[i] ch){return i;}}return npos;//没有找到} pos为0若没有传参给pos则默认从头开始找 查找字符串 size_t find(const char* s, size_t pos0){const char* p strstr(_strpos, s);//指向匹配字符串的首字符if (p){return p - _str;}else{return npos;//找不到}} 测试 void test() {djx::string s(hello world);size_t i s.find(world);cout i endl; } substr string substr(size_t pos, size_t len npos){string s;size_t end pos len;if (len npos || pos len _size)//从pos位置开始有多少取多少{len _size - pos;end _size;}s.reserve(len);//提前开空间避免多次扩容for (size_t i pos; i end; i){s _str[i];}return s;//传值返回} 拷贝构造 传统写法和现代写法在效率上区别不大只是代码简洁性的区分 传统写法 //传统写法string(const string s){_str new char[s._capacity 1];strcpy(_str, s._str);_size s._size;_capacity s._capacity;} 自己开和s一样大的空间拷贝数据 现代写法 void swap(string s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}//现代写法string(const string s):_str(nullptr),_size(0),_capacity(0){string tmp(s._str);//调用构造函数swap(tmp);} 让构造函数去生成tmp再与tmp交换 当tmp销毁时调用tmp的析构函数会把this指向的对象它申请的资源给释放掉 注意this指向的对象中的成员变量都要走初始化列表是它们定义的地方 那么如果不给this指向对象的成员变量初始化那么this指向的对象中的_str指向的是一块随机的空间是野指针不能随意释放这块不属于自己的空间 所以需要在初始胡列表的地方给this指向对象中的成员变量初始化 赋值重载 传统写法 //传统写法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;} 1 tmp指向一块与s一模一样的空间 2 释放_str指向的空间 3 _str指向tmp指向的空间 现代写法 版本1 //现代写法1string operator(const string s){if (this ! s){string tmp(s);//调用拷贝构造生成tmpswap(tmp);}return *this;} 版本2 //现代写法2string operator(string s)//拷贝构造生成s{swap(s);return *this;}s销毁会释放原本由*this对象申请的空间 测试: void test9() {djx::string s(test.cpp.tar.zip);size_t i s.find(.);cout i endl;djx::string sub s.substr(i);cout sub endl;djx::string s2(https://legacy.cplusplus.com/reference/string/string/rfind/);//分割 协议、域名、资源名djx::string sub1;djx::string sub2;djx::string sub3;size_t i1 s2.find(:);if (i1 ! djx::string::npos){sub1 s2.substr(0, i1);}else{cout 找不到i1 endl;}size_t i2 s2.find(/, i1 3);if (i2 ! djx::string::npos){sub2 s2.substr(i13, i2-(i13));}else{cout 找不到i2 endl;}sub3 s2.substr(i2 1);cout sub1 endl;cout sub2 endl;cout sub3 endl; } 注意1 substr是传值返回s对象出了作用域之后就销毁了会生成一个临时对象由s拷贝构造生成 若是我们没有写拷贝构造函数编译器默认生成的拷贝构造函数对于对象中内置类型的成员只会完成浅拷贝值拷贝即临时对象和s对象管理同一块空间但是s出了作用域之后会调用析构函数这块空间会被释放掉 substr返回的临时对象再拷贝构造给sub对象没写拷贝构造函数编译器生成的拷贝构造依然是值拷贝那么sub对象和临时对象管理同一块空间临时对象任务完成后销毁再次对已经释放的空间进行释放导致程序崩溃 这里还涉及编译器优化的问题 substr拷贝构造生成临时对象再由临时对象拷贝构造生成sub连续的拷贝构造动作编译器直接一步优化为一个拷贝构造让s在销毁前先拷贝构造生成sub即使是优化了也因为浅拷贝的问题导致程序崩溃- sub 和s管理同一块资源空间s销毁释放一次这块空间等sub销毁时再一次释放这块空间 所以拷贝构造必须由我们来写完成深拷贝让每个对象有自己独立的资源空间  注意2 解决拷贝构造问题后由原来的浅拷贝变为了深拷贝那么substr返回的临时对象就有和s一模一样的独立资源空间 但是若是我们没有写赋值重载函数那么编译器默认生成的赋值重载函数对于对象中的内置类型的成员只会浅拷贝即sub1和临时对象管理同一块空间且sub1原来管理的资源空间丢失导致内存泄漏且临时对象销毁对它管理的资源空间释放一次当sub1销毁又对这块空间释放一次程序崩溃 所以我们也要显示写赋值重载函数完成深拷贝让每个对象有自己独立的与赋值对象一模一样的资源空间而不是和其他对象共享同一块资源空间的管理 完结撒花~
http://www.zqtcl.cn/news/498231/

相关文章:

  • 电子商务个人网站可以备案吗短网址还原
  • 网站内容由什么组成部分组成部分电子商务网站建设主管的策划书
  • 云服务器安装win系统做网站seo三人行论坛
  • 电气网站设计机械设计软件solidworks
  • 内网网站建设所需硬件设备厦门关键词排名提升
  • 网站动态海报效果怎么做的最专业网站建
  • 学校如何建设网站北京市住房及城乡建设部网站
  • 响应式网站制作流程全国城建培训中心官网查询证书
  • 北京工程建设信息网站中国市场网
  • xml做网站源码免费网站是
  • 中国工商建设标准化协会网站织梦app网站模板
  • 怎么做好网络销售文大侠seo博客
  • wish网站应该怎么做网站建设前规划
  • 网站建设目的是什么建筑机械人才培训网官网
  • 建筑建设行业网站大型购物网站开发
  • 手机网站开发用什么设计之家网
  • 网站开发平台有哪些什么是网络开发
  • 学校网站前置审批网站做哪些比较有意思
  • 怎么给企业做网站学计算机网站建设
  • 网站关键词优化排名技巧aiyuan wordpress
  • 建设工程资质证书二维码扫描网站自己做的网站如何让qq登录
  • 网站域名有效期wordpress 特别慢
  • 建立个人网站服务器如何用dedecms做网站
  • php网站开发实市场推广策略 包括哪些
  • 合众商道网站开发可以投稿的写作网站
  • 北京贸易公司网站制作免费的查企业的网站
  • 网站建设报价表模板下载小程序怎么找出来
  • 网站制作简单协议wordpress快速建站教程视频教程
  • 杭州做网站价格北京企业响应式网站建设
  • 30个成功的电子商务网站设计中企动力 网站报价