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

长春网站建设方案优化来个网站吧好人一生平安

长春网站建设方案优化,来个网站吧好人一生平安,seo引擎优化专员,十四五专业建设规划前言 本篇博客继续为大家介绍类与对象的知识#xff0c;承接part1的内容#xff0c;本篇内容是类与对象的核心内容#xff0c;稍微有些复杂#xff0c;如果你对其感兴趣#xff0c;请继续阅读#xff0c;下面进入正文部分。 1. 类的默认成员函数 默认成员函数就是用户…前言 本篇博客继续为大家介绍类与对象的知识承接part1的内容本篇内容是类与对象的核心内容稍微有些复杂如果你对其感兴趣请继续阅读下面进入正文部分。 1. 类的默认成员函数 默认成员函数就是用户没有显式实现编译器会⾃动生成的成员函数称为默认成员函数。⼀个类我们不写的情况下编译器会默认生成以下6个默认成员函数需要注意的是这6个中最重要的是前4个最后两个取地址重载不重要我们稍微了解⼀下即可。其次就是C11以后还会增加两个默认成员函数 移动构造和移动赋值这个我们后面再介绍。默认成员函数很重要也比较复杂我们要从两个方面去学习 • 第⼀我们不写时编译器默认生成的函数行为是什么是否满足我们的需求。 • 第⼆编译器默认生成的函数不满足我们的需求我们需要自己实现那么如何自己实现 2. 构造函数  构造函数是特殊的成员函数需要注意的是构造函数虽然名称叫构造但是构造函数的主要任务并不是开空间创建对象(我们常使用的局部对象是栈帧创建时空间就开好了)而是对象实例化时初始化对象。构造函数的本质是要替代我们以前Stack和Date类中写的Init函数的功能构造函数自动调用的特点就完美地替代了Init。 构造函数的特点 1. 函数名与类名相同。 2. 无返回值。(返回值啥都不需要给也不需要写void不要纠结C规定如此) 3. 对象实例化时系统会自动调用对应的构造函数。 4. 构造函数可以重载。 5. 如果类中没有显式定义构造函数则C编译器会⾃动⽣成⼀个⽆参的默认构造函数⼀旦用户显式定义编译器将不再生成。 6. 无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数都叫做默认构造函数。但是这三个函数有且只有一个存在不能同时存在。无参构造函数和全缺省构造函数虽然构成函数重载但是调用时会存在歧义。要注意很多同学会认为默认构造函数是编译器默认生成那个叫默认构造实际上无参构造函数、全缺省构造函数也是默认构造总结⼀下就是不传实参就可以调用的构造就叫默认构造。 7. 我们不写编译器默认生成的构造对内置类型成员变量的初始化没有要求也就是说是是否初始化是不确定的看编译器。对于自定义类型成员变量要求调用这个成员变量的默认构造函数初始化。如果这个成员变量没有默认构造函数那么就会报错我们要初始化这个成员变量需要用初始化列表才能解决初始化列表我们下个章节再细细讲解。 说明C把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的原生数据类型 如int/char/double/指针等自定义类型就是我们使用class/struct等关键字自己定义的类型。 #includeiostream using namespace std; class Date { public:// 1.无参构造函数Date(){_year 1;_month 1;_day 1;}// 2.带参构造函数Date(int year, int month, int day){_year year;_month month;_day day;}// 3.全缺省构造函数/*Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}*/void Print(){cout _year / _month / _day endl;} private:int _year;int _month;int _day; }; int main() {// 如果留下三个构造中的第⼆个带参构造第⼀个和第三个注释掉// 编译报错error C2512: “Date”: 没有合适的默认构造函数可⽤Date d1;// 调用默认构造函数d1.Print();Date d2(2025, 1, 1); // 调用带参的构造函数d2.Print();// 注意如果通过无参构造函数创建对象时对象后⾯不⽤跟括号否则编译器⽆法// 区分这⾥是函数声明还是实例化对象// warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)//Date d3();//d1.Print();//d2.Print();return 0; } 这里大家注意我将3个成员函数全部注释了这个时候编译器就要调用默认生成的构造函数大家看到结果并没有进行初始化。所以这里说明一个点大多数情况下构造函数都需要我们自己去写编译器自己生成的不靠谱无法满足我们的需求。  #includeiostream using namespace std; typedef int STDataType; class Stack { public:Stack(int n 4){_a (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr _a){perror(malloc申请空间失败);return;}_capacity n;_top 0;}// ... private:STDataType* _a;size_t _capacity;size_t _top; }; // 两个Stack实现队列 class MyQueue { public://编译器默认⽣成MyQueue的构造函数调⽤了Stack的构造完成了两个成员的初始化 private:Stack pushst;Stack popst; }; int main() {MyQueue mq;return 0; } 这里我们可以总结构造函数都需要我们自己去实现少数情况类似MyQueue且Stack有默认构造时MyQueue自动生成就可以用。 #includeiostream using namespace std; typedef int STDataType; class Stack { public:Stack(int n){_a (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr _a){perror(malloc申请空间失败);return;}_capacity n;_top 0;}// ... private:STDataType* _a;size_t _capacity;size_t _top; }; // 两个Stack实现队列 class MyQueue { public://编译器默认⽣成MyQueue的构造函数调⽤了Stack的构造完成了两个成员的初始化 private:Stack pushst;Stack popst; }; int main() {MyQueue mq;return 0; }这里大家注意当我们将全缺省改成带参的编译器会报错这也就验证了上面的最后一条规则。 3. 析构函数 析构函数与构造函数功能相反析构函数不是完成对对象本⾝的销毁比如局部对象是存在栈帧的 函数结束栈帧销毁他就释放了不需要我们管C规定对象在销毁时会自动调用析构函数完成对象中资源的清理释放工作。析构函数的功能类比我们之前Stack实现的Destroy功能而像Date没有 Destroy其实就是没有资源需要释放所以严格说Date是不需要析构函数的。综上有资源申请的类就需要写析构函数。 析构函数的特点 1. 析构函数名是在类名前加上字符~。  2. 无参数无返回值。(这⾥跟构造类似也不需要加void) 3. ⼀个类只能有⼀个析构函数。若未显式定义系统会自动生成默认的析构函数。 4. 对象生命周期结束时系统会自动调用析构函数。 5. 跟构造函数类似我们不写编译器⾃动⽣成的析构函数对内置类型成员不做处理自定义类型成员会调用它自己的析构函数。   6. 还需要注意的是我们显示写析构函数对于⾃定义类型成员也会调⽤他的析构也就是说自定义类型成员无论什么情况都会自动调用析构函数。 7. 如果类中没有申请资源时析构函数可以不写直接使用编译器生成的默认析构函数如Date如果默认生成的析构就可以用也就不需要显示写析构如MyQueue但是有资源申请时⼀定要自己写析构否则会造成资源泄漏如Stack。 8. ⼀个局部域的多个对象C规定后定义的先析构。 #includeiostream using namespace std; typedef int STDataType; class Stack { public:Stack(int n 4){_a (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr _a){perror(malloc申请空间失败);return;}_capacity n;_top 0;}~Stack(){cout ~Stack() endl;free(_a);_a nullptr;_top _capacity 0;} private:STDataType* _a;size_t _capacity;size_t _top; }; // 两个Stack实现队列 class MyQueue { public://编译器默认⽣成MyQueue的析构函数调⽤了Stack的析构释放的Stack内部的资源 // 显⽰写析构也会⾃动调⽤Stack的析构/*~MyQueue(){}*/ private:Stack pushst;Stack popst; }; int main() {Stack st;MyQueue mq;return 0; }对比⼀下用C和C实现的Stack解决之前括号匹配问题isValid我们发现有了构造函数和析构函数确实方便了很多不会再忘记调用Init和Destory函数了也方便了不少。  #includeiostream using namespace std; // ⽤最新加了构造和析构的C版本Stack实现 bool isValid(const char* s) {Stack st;while (*s){if (*s [ || *s ( || *s {){st.Push(*s);}else{// 右括号⽐左括号多数量匹配问题if (st.Empty()){return false;}// 栈⾥⾯取左括号char top st.Top();st.Pop(); // 顺序不匹配if ((*s ] top ! [)|| (*s } top ! {)|| (*s ) top ! ()){return false;}}s;}// 栈为空返回真说明数量都匹配 左括号多右括号少匹配问题return st.Empty(); } // ⽤之前C版本Stack实现 bool isValid(const char* s) {ST st;STInit(st);while (*s){// 左括号⼊栈if (*s ( || *s [ || *s {){STPush(st, *s);}else // 右括号取栈顶左括号尝试匹配{if (STEmpty(st)){STDestroy(st);return false;}char top STTop(st);STPop(st);// 不匹配if ((top ( *s ! ))|| (top { *s ! })|| (top [ *s ! ])){STDestroy(st);return false;} }s;}// 栈不为空说明左括号⽐右括号多数量不匹配bool ret STEmpty(st);STDestroy(st);return ret; } int main() {cout isValid([()][]) endl;cout isValid([(])[]) endl;return 0; } 4. 拷贝构造函数  如果⼀个构造函数的第⼀个参数是自身类类型的引用且任何额外的参数都有默认值则此构造函数也叫做拷贝构造函数也就是说拷贝构造是⼀个特殊的构造函数。 拷贝构造的特点 1. 拷贝构造函数是构造函数的⼀个重载。 2. 拷贝构造函数的参数第一个参数必须是类类型对象的引用使用传值方式编译器直接报错因为语法逻辑上会引发无穷递归调用。  3. C规定自定义类型对象进行拷贝行为必须调用拷贝构造所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成。 4. 若未显式定义拷贝构造编译器会自动生成拷贝构造函数。自动生成的拷贝构造对内置类型成 员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝)对⾃定义类型成员变量会调用他的拷贝构 造。这里要注意与构造和析构不同拷贝构造对内置类型也会进行处理。 #includeiostream using namespace std; class Date { public:Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}// 编译报错error C2652: “Date”: ⾮法的复制构造函数: 第⼀个参数不应是“Date”//Date(Date d)//Date(const Date d)//{// _year d._year;// _month d._month;// _day d._day;//}//Date(Date* d)//{// _year d-_year;// _month d-_month;// _day d-_day;//}void Print(){cout _year - _month - _day endl;} private:int _year;int _month;int _day; }; int main() {Date d1(2024, 7, 5);// C规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造所以这⾥传值传参要调⽤拷⻉构造// 所以这⾥的d1传值传参给d要调⽤拷⻉构造完成拷⻉传引⽤传参可以较少这⾥的拷⻉//Func1(d1);//cout d1 endl;//这⾥可以完成拷⻉但是不是拷⻉构造只是⼀个普通的构造//Date d2(d1);//d1.Print();//d2.Print();//这样写才是拷⻉构造通过同类型的对象初始化构造⽽不是指针Date d3(d1);d3.Print();// 也可以这样写这⾥也是拷⻉构造Date d4 d1;d4.Print();return 0; } 这里大家通过代码就能看到我们没有将前面写的拷贝构造函数注释掉了但是依然可以得到相应的结果这就是因为编译器自动生成的拷贝构造函数对内置类型进行了值拷贝。 5. 像Date这样的类成员变量全是内置类型且没有指向什么资源编译器⾃动⽣成的拷⻉构造就可以完成需要的拷贝所以不需要我们显⽰实现拷⻉构造。像Stack这样的类虽然也都是内置类型但是_a指向了资源编译器⾃动⽣成的拷⻉构造完成的值拷贝/浅拷贝不符合我们的需求所以需要我们自己实现深拷贝(对指向的资源也进行拷贝)。像MyQueue这样的类型内部主要是⾃定义类型Stack成员编译器⾃动⽣成的拷贝构造会调⽤Stack的拷贝构造也不需要我们显示实现 MyQueue的拷⻉构造。这里还有⼀个小技巧如果一个类显示实现了析构并释放资源那么他就 需要显示写拷贝构造否则就不需要。 6. 传值返回会产⽣⼀个临时对象调用拷贝构造传值引用返回返回的是返回对象的别名(引⽤)没有产⽣拷贝。但是如果返回对象是⼀个当前函数局部域的局部对象函数结束就销毁了那么使用引用返回是有问题的这时的引用相当于⼀个野引用类似⼀个野指针⼀样。传引用返回可以减少拷贝但是⼀定要确保返回对象在当前函数结束后还在才能用引用返回。 #includeiostream using namespace std; class Date { public:Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}// 编译报错error C2652: “Date”: ⾮法的复制构造函数: 第⼀个参数不应是“Date”//Date(Date d)Date(const Date d){_year d._year;_month d._month;_day d._day;}//Date(Date* d)//{// _year d-_year;// _month d-_month;// _day d-_day;//}void Print(){cout _year - _month - _day endl;} private:int _year;int _month;int _day; }; void Func1(Date d) {cout d endl;d.Print(); } // Date Func2() Date Func2() {Date tmp(2024, 7, 5);tmp.Print();return tmp; } int main() {Date d1(2024, 7, 5);// C规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造所以这⾥传值传参要调⽤拷⻉构造// 所以这⾥的d1传值传参给d要调⽤拷⻉构造完成拷⻉传引⽤传参可以较少这⾥的拷⻉//Func1(d1);//cout d1 endl;//这⾥可以完成拷⻉但是不是拷⻉构造只是⼀个普通的构造//Date d2(d1);//d1.Print();//d2.Print();//这样写才是拷⻉构造通过同类型的对象初始化构造⽽不是指针Date d3(d1);d3.Print();// 也可以这样写这⾥也是拷⻉构造Date d4 d1;d4.Print();// Func2返回了⼀个局部对象tmp的引⽤作为返回值// Func2函数结束tmp对象就销毁了相当于了⼀个野引⽤//Date ret Func2();//ret.Print();return 0; } 5. 赋值运算符重载  5.1 运算符重载 • 当运算符被用于类类型的对象时C语言允许我们通过运算符重载的形式指定新的含义。C规定类类型对象使用运算符时必须转换成调用对应运算符重载若没有对应的运算符重载则会编译报错。 • 运算符重载是具有特殊名字的函数他的名字是由operator和后面要定义的运算符共同构成。和其他函数⼀样它也具有其返回类型和参数列表以及函数体。 • 重载运算符函数的参数个数和该运算符作用的运算对象数量⼀样多。⼀元运算符有⼀个参数⼆元运算符有两个参数二元运算符的左侧运算对象传给第⼀个参数右侧运算对象传给第⼆个参数。 • 如果⼀个重载运算符函数是成员函数则它的第⼀个运算对象默认传给隐式的this指针因此运算符重载作为成员函数时参数比运算对象少⼀个。 • 运算符重载以后其优先级和结合性与对应的内置类型运算符保持⼀致。 • 不能通过连接语法中没有的符号来创建新的操作符比如operator。 • .* 、:: 、sizeof 、?:、 . 注意以上5个运算符不能重载。(选择题里面常考大家要记⼀ 下) • 重载操作符至少有⼀个类类型参数不能通过运算符重载改变内置类型对象的含义如 int operator(int x, int y) • ⼀个类需要重载哪些运算符是看哪些运算符重载后有意义比如Date类重载operator-就有意 义但是重载operator就没有意义。 • 重载运算符时有前置和后置运算符重载函数名都是operator无法很好的区分。 C规定后置重载时增加⼀个int形参跟前置构成函数重载方便区分。 •重载和时需要重载为全局函数因为重载为成员函数this指针默认抢占了第⼀个形参位 置第⼀个形参位置是左侧运算对象调⽤时就变成了对象cout不符合习惯和可读性。重载为全局函数把ostream/istream放到第⼀个形参位置就可以了第二个形参位置当类类型对象。 #includeiostream using namespace std; class Date { public:Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}void Print(){cout _year - _month - _day endl;}bool operator(const Date d){return _year d._year _month d._month _day d._day;}Date operator(){cout 前置 endl;//...return *this;}Date operator(int){Date tmp;cout 后置 endl;//...return tmp;} private:int _year;int _month;int _day; };int main() {Date d1(2024, 7, 5);Date d2(2024, 7, 6);// 运算符重载函数可以显⽰调⽤d1.operator(d2);// 编译器会转换成 d1.operator(d2);d1 d2;// 编译器会转换成 d1.operator();d1;// 编译器会转换成 d1.operator(0);d1;return 0; } 5.2 赋值运算符重载 赋值运算符重载是⼀个默认成员函数⽤于完成两个已经存在的对象直接的拷贝赋值这⾥要注意跟拷贝构造区分拷贝构造⽤于⼀个对象拷贝初始化给另⼀个要创建的对象。 赋值运算符重载的特点 1. 赋值运算符重载是⼀个运算符重载规定必须重载为成员函数。赋值运算重载的参数建议写成 const当前类类型引用否则会传值传参会有拷贝。这里注意与前面的拷贝构造进行区分拷贝构造要求第一个参数必须为类类型的引用那里是为了防止无穷递归而在赋值运算符重载这里我们是建议参数写成类类型对象的引用这么做可以减少拷贝这里还要说明一点我们最好都带上const这样形参就不会被改变。 2. 有返回值且建议写成当前类类型引用引用返回可以提高效率有返回值⽬的是为了⽀持连续赋值场景。 3. 没有显式实现时编译器会⾃动⽣成⼀个默认赋值运算符重载默认赋值运算符重载行为跟默认拷贝构造函数类似对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝)对⾃定义类型成员变量会调用它的赋值重载。 4. 像Date这样的类成员变量全是内置类型且没有指向什么资源编译器⾃动⽣成的赋值运算符重载就 可以完成需要的拷贝所以不需要我们显示实现赋值运算符重载。像Stack这样的类虽然也都是内置类型但是_a指向了资源编译器⾃动生成的赋值运算符重载完成的值拷贝/浅拷贝不符合我 们的需求所以需要我们⾃⼰实现深拷贝(对指向的资源也进行拷贝)。像MyQueue这样的类型内部 主要是⾃定义类型Stack成员编译器⾃动生成的赋值运算符重载会调⽤Stack的赋值运算符重载 也不需要我们显示实现MyQueue的赋值运算符重载。这⾥还有⼀个小技巧如果⼀个类显示实现了析构并释放资源那么它就需要显示写赋值运算符重载否则就不需要。 class Date {public:Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}Date(const Date d){cout Date(const Date d) endl;_year d._year;_month d._month;_day d._day;}// 传引⽤返回减少拷⻉// d1 d2;Date operator(const Date d){// 不要检查⾃⼰给⾃⼰赋值的情况if (this ! d){_year d._year;_month d._month;_day d._day;}// d1 d2表达式的返回对象应该为d1也就是*thisreturn *this;}void Print(){cout _year - _month - _day endl;} private:int _year;int _month;int _day; }; int main() { Date d1(2024, 7, 5);Date d2(d1);Date d3(2024, 7, 6);d1 d3;// 需要注意这⾥是拷⻉构造不是赋值重载// 请牢牢记住赋值重载完成两个已经存在的对象直接的拷⻉赋值// ⽽拷⻉构造⽤于⼀个对象拷⻉初始化给另⼀个要创建的对象Date d4 d1;return 0; } 5.3 日期类的实现 关于日期类的实现我们就需要用到大量的运算符重载 首先为大家介绍Date.h Date.h 6. 取地址运算符重载 6.1 const成员函数 • 将const修饰的成员函数称之为const成员函数const修饰成员函数放到成员函数参数列表的后 面。 • const实际修饰该成员函数隐含的this指针表明在该成员函数中不能对类的任何成员进行修改。 const修饰Date类的Print成员函数Print隐含的this指针由 Date* const this 变为 const Date* const this。 简单来说如果我们不想让函数中的成员变量发生改变就可以加上const。 #includeiostream using namespace std; class Date { public:Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}// void Print(const Date* const this) constvoid Print() const{cout _year - _month - _day endl;} private:int _year;int _month;int _day; }; int main() {// 这⾥⾮const对象也可以调⽤const成员函数是⼀种权限的缩⼩Date d1(2024, 7, 5);d1.Print();const Date d2(2024, 8, 5);d2.Print();return 0; }6.2 取地址运算符重载 取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载⼀般这两个函数编译器⾃动 ⽣成的就可以够我们⽤了不需要去显示实现。除非⼀些很特殊的场景⽐如我们不想让别⼈取到当 前类对象的地址就可以⾃⼰实现⼀份胡乱返回⼀个地址。 class Date { public :Date* operator(){return this;// return nullptr;} const Date* operator()const{return this;// return nullptr;} private :int _year ; // 年int _month ; // ⽉int _day ; // ⽇ };这个内容大家作为了解一般取地址运算符是不需要我们自己来重载的。 7. 总结 本篇博客继续为大家介绍了类和对象的内容本篇中提到的也是类和对象中的核心内容理解难度也较大所以希望大家可以掌握好这里这对后面学习C的内容非常重要最后希望本篇博客可以为大家带来帮助感谢阅读
http://www.zqtcl.cn/news/303709/

相关文章:

  • 青岛网站推广方案网线制作心得与体会
  • 杭州网站优化公司哈尔滨企业网站模板建站
  • 洛阳免费网站建设自己做网站最新视频教程
  • 网站备案查询 美橙网开发app需要的技术
  • 软件产品如何做网站推广昆山外贸网站建设推广
  • 景德镇市城市建设规划网站wordpress用不了了
  • 网站及新媒体建设宣传片wordpress 无法编辑主题
  • 东莞设计网站重庆做腋臭骑士网站
  • 什么软件可以搜索关键词精准网站信息优化的方式
  • 购物网站排名前十名山东泰安建筑工程集团有限公司
  • 源码下载站用vs网站开发
  • 自己做网站seo彩票的网站怎么做
  • 如何在网站后台找到死链接网站内页权重查询
  • 专业做国际网站网站开发的编程软件
  • 如何运营垂直网站网页工具大全
  • 如何让自己做的网站可以播放歌曲做培训网站
  • 做网站的毕业设计网站没备案怎么做淘宝客
  • 百度申诉网站建设银行住房租赁代表品牌是什么
  • 网站初期推广方案虚拟服务器搭建wordpress
  • jeecms可以做网站卖吗山西网络推广专业
  • 2017 如何做网站优化育儿哪个网站做的好
  • 网站制作容易吗青岛网站建设公司报价
  • 淘宝建设网站的好处网站制作结构
  • 网站开发网站建设公司临沂网站建设找谁
  • 咋么做网站在电脑上潍坊免费模板建站
  • 苏州网站建设推广咨询平台做网站的公司图
  • 北京企业网站怎么建设免费给我推广
  • 网站制作价钱多少专业的咨询行业网站制作
  • 做百度网站每年的费用多少交换友情链接时需要注意的事项
  • 怎么在百度网站上做自己的网站百度开户渠道