外网如何查看局域网建设的网站,wordpress 外网,海宁市网站建设,电影订票网站开发一、类的默认成员函数 默认成员函数从名字就告诉我们何为默认成员函数#xff0c;即#xff1a;用户没有实现#xff0c;编译器默认自动实现的函数。 这时你不禁一喜#xff0c;还有这好事#xff0c;编译器给我打工#xff0c;那么#xff0c;我们今天都来了解一下都有…一、类的默认成员函数 默认成员函数从名字就告诉我们何为默认成员函数即用户没有实现编译器默认自动实现的函数。 这时你不禁一喜还有这好事编译器给我打工那么我们今天都来了解一下都有哪些牛马函数但是提醒一下有的函数在某些情况下需要手动实现 1.1 构造函数 构造函数是啥顾名思义把该函数成员变量构造出来不不不虽然他叫构造但它和各位一样有一颗叛逆的心它的实际作用是实例化对象也就是初始化对象各位记住创建对象是栈帧开启时就创建好了。就好比我们之前写过的数据结构构造函数的作用就是Init函数。 函数特点 1. 函数名与类名相同。                 2. ⽆返回值。 (返回值啥都不需要给也不需要写void不要纠结C规定如此)                 3. 对象实例化时系统会⾃动调⽤对应的构造函数。                 4. 构造函数可以重载。                 5. 如果类中没有显式定义构造函数则C编译器会⾃动⽣成⼀个⽆参的默认构造函数⼀旦⽤户显 式定义编译器将不再⽣成。                 6. ⽆参构造函数、全缺省构造函数、我们不写构造时编译器默认⽣成的构造函数都叫做默认构造函 数。但是这三个函数有且只有⼀个存在不能同时存在。⽆参构造函数和全缺省构造函数虽然构成 函数重载但是调⽤时会存在歧义。要注意很多人会认为默认构造函数是编译器默认⽣成那个叫 默认构造实际上⽆参构造函数、全缺省构造函数也是默认构造总结⼀下就是不传实参就可以调 ⽤的构造就叫默认构造。 一下便是咱们手动实现的构造函数 
class Data
{
public:Data()								//无参构造{_year  1;_month  1;_day  1;}Data(int year, int month, int day)	//带参构造{_year  year;_month  month;_day  day;}//Data(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()
{Data d1;           // 调用默认构造Data d2(2024, 7, 1);d1.Print();d2.Print();return 0;
} 咱们注意一下全缺省构造与无参构造不能同时出现这样会引起编译器报错。为啥因为都不用传参数如果你是编译器你会调哪个掉这个那个不满调那个这个又不满。所以只能禁止这种行为了不然会有以下报错 咱们现在想我之前不是说过函数会自动调用吗?是的演示代码如下 
class Data
{
private:int _year;int _month;int _day;
};int main()
{Data d;return 0;
} 咱们调式来看 我们可以看到生成是生成了不过都是随机值那有什么处理办法吗还真有如下 
class Data
{
private:int _year  1;int _month  1;int _day  1;
}; 这样处理即可咱们调试来看。 果然如咱们所愿。构造函数咱们先了解到这我们随后再行探讨。 1.2 析构函数  析构函数功能与构造函数功能相反构造是初始化析构就是完成对对象的资源整理工作。比如C语言中的malloc、calloc、realloc等资源释放工作。 析构函数特点如下 1. 析构函数名是在类名前加上字符 ~。                 2. ⽆参数⽆返回值。 (这⾥跟构造类似也不需要加void)                 3. ⼀个类只能有⼀个析构函数。若未显式定义系统会⾃动⽣成默认的析构函数。                 4. 对象⽣命周期结束时系统会⾃动调⽤析构函数。                 5. 跟构造函数类似我们不写编译器⾃动⽣成的析构函数对内置类型成员不做处理⾃定类型成员会 调⽤他的析构函数。                 6. 还需要注意的是我们显⽰写析构函数对于⾃定义类型成员也会调⽤他的析构也就是说⾃定义类 型成员⽆论什么情况都会⾃动调⽤析构函数。                  7. 如果类中没有申请资源时析构函数可以不写直接使⽤编译器⽣成的默认析构函数但是有资源申请时⼀定要 ⾃⼰写析构否则会造成资源泄漏。                 8. ⼀个局部域的多个对象C规定后定义的先析构。 class Stack
{
public:Stack(int n  4){int* tmp  (int*)malloc(sizeof(int) * 4);if (tmp  nullptr){perror(malloc fail);return;}_a  tmp;_capacity  n;_size  0;}~Stack(){cout  ~Stack()  endl;free(_a);_a  nullptr;_capacity  0;_size  0;}
private:int* _a;int _capacity;int _size;
}; 以上是一个简单的结构我们可通过其析构打印来判断是否调用析构。大家可自行下去检验。 对于其特点大家可着重注意以下最后一点析构是执照定义先后顺序来经行析构的。 
class Test
{
public:Test(int vale){_vale  vale;}~Test(){cout  _vale  ~Test()  endl;}
private:int _vale;
};int main()
{Test T1(1);Test T2(2);return 0;
} 以上代码析构顺序是什么样呢答案为先二后一。 1.3 拷⻉构造函数 拷贝构造函数是啥既然有构造二字莫非是构造函数的一个子集是的拷贝构造是一种特殊的构造函数。 如果⼀个构造函数的第⼀个参数是⾃⾝类类型的引⽤且任何额外的参数都有默认值则此构造函数 也叫做拷⻉构造函数也就是说拷⻉构造是⼀个特殊的构造函数。 函数特点如下 1. 拷⻉构造函数是构造函数的⼀个重载。                 2. 拷⻉构造函数的参数只有⼀个且必须是类类型对象的引⽤使⽤传值⽅式编译器直接报错因为语 法逻辑上会引发⽆穷递归调⽤。                 3. C规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造所以这⾥⾃定义类型传值传参和传值返 回都会调⽤拷⻉构造完成。                 4. 若未显式定义拷⻉构造编译器会⽣成⾃动⽣成拷⻉构造函数。⾃动⽣成的拷⻉构造对内置类型成 员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉)对⾃定义类型成员变量会调⽤他的拷⻉构 造。                5.如果浅拷贝不符合我们的要求我们就要手动实现拷贝构造。⼩技巧如果⼀个类显⽰实现了析构并释放资源那么他就 需要显⽰写拷⻉构造否则就不需要。                 6. 传值返回会产⽣⼀个临时对象调⽤拷⻉构造传值引⽤返回返回的是返回对象的别名(引⽤)没 有产⽣拷⻉。但是如果返回对象是⼀个当前函数局部域的局部对象函数结束就销毁了那么使⽤ 引⽤返回是有问题的这时的引⽤相当于⼀个野引⽤类似⼀个野指针⼀样。传引⽤返回可以减少 拷⻉但是⼀定要确保返回对象在当前函数结束后还在才能⽤引⽤返回。  这里解释一下第六条  class Data
{
public:Data(int year, int month, int day){_year  year;_month  month;_day  day;}Data(const Data d)				//这里我们不希望修改该值为了避免出错放前置const即可{_year  d._year;_month  d._month;_day  d._day;}
private:int _year;int _month;int _day;
};int main()
{Data d1(2020, 1, 1);Data d2(d1);Data d4  d1;		//该方式为拷贝构造//赋值为两个初始化好的两个对象//这里的d4还未初始化故为拷贝构造return 0;
} 
二、运算符重载 2.1 取地址运算符重载 取地址运算符重载就是对这个符号就行重新实现在日常当我们不想叫别人用我们的地址时便可用其运算符重载。为了实现该目的我们要用到该函数名operator和该符号组成。 
class Data
{
public:Data* operator(){return this;//此处放回值由你来决定}
private:int _year;int _month;int _day;
}; 2.2 运算符重载 从上述例子我们可以看出C允许我们对运算符进行重载把它变为以operator开头和符号名开头的函数。以下爱上运算符重载的特点 重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多。⼀元运算符有⼀个参数⼆元运算符有两个参数⼆元运算符的左侧运算对象传给第⼀个参数右侧运算对象传给第⼆个参数。          如果⼀个重载运算符函数是成员函数则它的第⼀个运算对象默认传给隐式的this指针因此运算 符重载作为成员函数时参数⽐运算对象少⼀个。         运算符重载以后其优先级和结合性与对应的内置类型运算符保持⼀致。         不能通过连接语法中没有的符号来创建新的操作符⽐如operator         .*         ::         sizeof         ?:         . 注意以上5个运算符不能重载。         重载操作符⾄少有⼀个类类型参数不能通过运算符重载改变内置类型对象的含义。         个类需要重载哪些运算符是看哪些运算符重载后有意义。         重载运算符时有前置和后置运算符重载函数名都是operator⽆法很好的区分。 C规定后置重载时增加⼀个int形参跟前置构成函数重载⽅便区分。         重载和时需要重载为全局函数因为重载为成员函数this指针默认抢占了第⼀ 个形参位 置第⼀个形参位置是左侧运算对象调⽤时就变成了对象cout不符合使⽤习惯和可读性。  class Data
{
public:void func(){cout  _year  /  _month  /  _day  endl;}bool operator(Data d){return _year  d._year _month  d._month _day  d._day;}Data operator()			//前置{_day;return *this;}Data operator(int)		//后置  里面int可理解为区分符不用过多关注{Data tmp(*this);_day;return tmp;}friend ostream operator(ostream out, const Data d);friend istream operator( istream in, Data d);			// 此处为友元函数后续会进行讲解
private:int _year;int _month;int _day;
};// 与  运算符重载
ostream operator(ostream out, const Data d)				//此处const保证输出不进行改变
{out  d._year  d._month  d._day  endl;return out;
}
istream operator( istream in, Data d)
{in  d._year  d._month  d._day;return in;
}三、在探构造函数 经过以上的学习相信大家对于类和对象已经有了一定的掌握接下来来了解一下更深层次的构造函数。 之前我们实现构造函数时初始化成员变量主要使⽤函数体内赋值构造函数初始化还有⼀种⽅式就是初始化列表初始化列表的使⽤⽅式是以⼀个冒号开始接着是⼀个以逗号分隔的数据成 员列表每个成员变量后⾯跟⼀个放在括号中的初始值或表达式。         每个成员变量在初始化列表中只能出现⼀次语法理解上初始化列表可以认为是每个成员变量定义 初始化的地⽅。         引⽤成员变量const成员变量没有默认构造的类类型变量必须放在初始化列表位置进⾏初始化否则会编译报错。         C11⽀持在成员变量声明的位置给缺省值这个缺省值主要是给没有显⽰在初始化列表初始化的 成员使⽤的。          尽量使⽤初始化列表初始化因为那些你不在初始化列表初始化的成员也会⾛初始化列表如果这 个成员在声明位置给了缺省值初始化列表会⽤这个缺省值初始化。如果你没有给缺省值对于没 有显⽰在初始化列表初始化的内置类型成员是否初始化取决于编译器C并没有规定。对于没有 显⽰在初始化列表初始化的⾃定义类型成员会调⽤这个成员类型的默认构造函数如果没有默认构 造会编译错误。          初始化列表中按照成员变量在类中声明顺序进⾏初始化跟成员在初始化列表出现的的先后顺序⽆关。建议声明顺序和初始化列表顺序保持⼀致。 class Data
{
public:Data():_year(1),_month(1),_day(1){cout  _year  _month  _day;}
private:int _year;int _month;int _day;
}; 明白了这些来出一道题来考一考大家 下⾯程序的运⾏结果是什么 A. 输出 1 1         B. 输出 2 2         C. 编译报错        D. 输出 1 随机值         E. 输出 1 2         F. 输出 2 1 
#includeiostream
using namespace std;
class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {cout  _a1     _a2  endl;}
private:int _a2  2;int _a1  2;
};
int main()
{A aa(1);aa.Print();
} 答案为D。为何上面我们说过初始化我们会按照声明的顺序进行初始化声明_a2靠前所以先对_a2进行初始化但此时_a1还未完成初始化所以为随机值。_a1大家应该能明白便不在赘述。 
四、static成员 static成员注意以下几点即可 ⽤static修饰的成员变量称之为静态成员变量静态成员变量⼀定要在类外进⾏初始化。         静态成员变量为所有类对象所共享不属于某个具体的对象不存在对象中存放在静态区。         ⽤static修饰的成员函数称之为静态成员函数静态成员函数没有this指针。         静态成员函数中可以访问其他的静态成员但是不能访问⾮静态的因为没有this指针。         ⾮静态的成员函数可以访问任意的静态成员变量和静态成员函数。          突破类域就可以访问静态成员可以通过类名::静态成员 或者 对象.静态成员 来访问静态成员变量 和静态成员函数。静态成员也是类的成员受public、protected、private 访问限定符的限制。         静态成员变量不能在声明位置给缺省值初始化因为缺省值是个构造函数初始化列表的静态成员 变量不属于某个对象不⾛构造函数初始化列表。 class A
{
public:A(){_scount;}A(const A t){_scount;}~A(){--_scount;}static int GetACount(){return _scount;}
private:// 类⾥⾯声明static int _scount;
};
// 类外⾯初始化
int A::_scount  0;
int main()
{cout  A::GetACount()  endl;A a1, a2;A a3(a1);cout  A::GetACount()  endl;cout  a1.GetACount()  endl;return 0;
} 大家可自行验证一下输出结果这里说明一下_scount为静态的不在类中存储。 
五、友元 友元分为友元类和友元函数。友元友元顾名思义就可以想成朋友我是你的朋友所以我可以访问你里面的对象对吧其访问方式简单即在类和函数前面friend即可访问。有以下注意点 外部友元函数可访问类的私有和保护成员友元函数仅仅是⼀种声明他不是类的成员函数。         友元函数可以在类定义的任何地⽅声明不受类访问限定符限制。         ⼀个函数可以是多个类的友元函数。         友元类中的成员函数都可以是另⼀个类的友元函数都可以访问另⼀个类中的私有和保护成员。          友元类的关系是单向的不具有交换性⽐如A类是B类的友元但是B类不是A类的友元。         友元类关系不能传递如果A是B的友元 B是C的友元但是A不是B的友元。         有时提供了便利。但是友元会增加耦合度破坏了封装所以友元不宜多⽤。 class B;						//此处为类的声明
class A
{friend void func(A a, B b);
private:int _a;
};
class B
{friend void func(A a, B b);
private:int _b;
};
void func(A a, B b)
{cout  a._a  endl;cout  b._b  endl;
} 完