💓博主CSDN主页:杭电码农-NEO💓
⏩专栏分类:C++初阶之路⏪
🚚代码仓库:NEO的学习日记🚚
🌹关注我🫵带你学习C++
🔝🔝
类和对象
- 1. 前言
- 2. 初始化列表
- 2.1初始化列表的作用
- 2.2 初始化列表再理解
- 3. static成员
- 4. 友元的概念
- 4.1 友元类
- 5. 类的匿名对象
- 6. 总结以及拓展
1. 前言
关于类和对象的大致内容已经结束
本篇文章主要是介绍一些冗杂的细节
虽然本节的内容属于对类和对象锦上添花
但在很多特定的场所下,还是特别使用的!
本章重点:
本篇文章重点讲解初始化列表
友元,匿名对象和类中的static成员
并且介绍类中的内部类的概念
话不多说,进入正题!
2. 初始化列表
构造函数中,为一个成员赋值
不能叫做对此成员初始化
只能说对此成员赋初始值
由此引出初始化列表:
真正初始化成员变量的地方!
初始化列表:
以冒号开始接着以逗号分隔的成员列表
每个"成员变量"后面跟一个
放在括号中的初始值或表达式
例如:
class Date
{
public:
Date(int year, int month, int day): _year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
初始化列表不止可以像上面一样用
还可以在函数体中再次对变量操作:
Date(int year, int month, int day): _year(year), _month(month), _day(day){_year++;_day--;}//或者这样Date(int year, int month, int day): _year(year), _month(month){_month = month;}
2.1初始化列表的作用
有些变量在初始化时必须对它赋值
比如:
- const成员变量
- 引用成员变量
- 没有默认构造的自定义类型成员
然而在构造函数函数体中的赋值
不叫对变量初始化,用上面的类型会报错
所以此时必须用初始化列表
class B
{
public:B(int a, int ref):_aobj(a),_ref(ref),_n(10){}
private:A _aobj; // 没有默认构造函数的自定义类型int& _ref; // 引用成员const int _n; // const修饰成员
};
在之后的学习中,尽量使用初始化列表
进行初始化,因为对于自定义成员来说
不管有没有显示写初始化列表
它都会优先使用初始化列表初始化
2.2 初始化列表再理解
初始化列表中,初始化变量的顺序
是变量在类中声明的顺序
比如以下代码:
class A
{
public:A(int a):_a1(a),_a2(_a1){}
private:int _a2;int _a1;
};
int main() {A aa(1);
}
此时,_a2会先初始化,_a1再初始化
_a2初始化时_a1还是随机值
所以_a2就被初始化成了随机值
而_a1会被初始化为1!
对于C++11缺省值的理解:
成员变量声明时给的缺省值
实际上就是给初始化列表的!
当用户没有显示传参初始化时
编译器会用用户定义的缺省值
当用户显示传参后,缺省值失效
使用用户传的值初始化!
class A
{
public:A(int a)//没有显示传参就用缺省值初始化:_a1(a),_a2(a){}
private:int _a2 = 1;int _a1 = 2;
};
}
3. static成员
概念:
-
声明为static的类成员称为类的静态成员
-
用static修饰的成员变量
称之为静态成员变量 -
用static修饰的成员函数
称之为静态成员函数 -
静态成员变量一定要在类外进行初始化
static成员的特性:
-
静态成员为所有类对象共享,放在静态区
-
静态成员变量必须在类外定义
类中只是声明 -
类静态成员即可用
类名::静态成员
或对象.静态成员
访问 -
静态成员函数没有隐藏的this指针
不能访问任何非静态成员 -
静态成员受访问限定符的限制
使用举例:
class B
{
public:static int Add(int x,int y);//没有this指针,无法访问类中成员static int a;//在类中声明
};
int B::a = 10;//在类外定义
此类的所有成员共同享有这个静态变量
4. 友元的概念
假设一个函数我想定义在类外
但是我又想访问类中的私有成员
只能将私有成员改为共有再访问
这种操作就破坏了类的封装!
引入友元解决此问题:
友元函数可以直接访问类的私有成员
它是定义在类外部的函数,不属于任何类
但需要在类的内部声明
声明时需要加friend关键字
举例说明:
class Date
{friend int Add(int x,int y);//友元函数的声明
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};int Add(int x,int y)//友元函数的定义
{x+=_year;y+=_month-_day;return x+y;
}
对友元函数的说明:
- 友元函数可访问类的私有和保护成员
但不是类的成员函数 - 友元函数不能用const修饰
- 友元函数可以在类定义的任何地方声明
不受类访问限定符限制 - 一个函数可以是多个类的友元函数
- 友元函数的调用与普通函数相同
4.1 友元类
除了有友元函数可以访问类私有成员外
声明友元类也可以达到一样的效果
内部类就是友元类的典型代表!
注:sizeof(外部类)的大小和内部类无关
class A
{
private:static int k;int h;
public:class B // B天生就是A的友元{public:void foo(const A& a){cout << k << endl;//OKcout << a.h << endl;//OK}};
};
5. 类的匿名对象
先定义一个类:
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
使用匿名对象:
Date d = Date(2023,8,1);
这里的:Date(2023,8,1)就是匿名对象
特点:
- 生命周期只有一行
- 没有名字,在初始化或销毁时
自动调用构造或析构函数
匿名对象使用场景:
当定义第一个变量只是为了调用
类中的一个函数,并且调用完后
此变量不会再被使用,此时可用匿名对象
匿名对象极大的简化了代码行!
6. 总结以及拓展
类和对象的所有内容已经讲解完毕
若友遗漏或不对的地方,请在评论指出!
拓展:explicit关键字
构造函数不仅能构造和初始化对象
对于单个参数或除第一个参数无默认值
其余均有默认值的构造函数
还有隐式类型转换的作用
比如:
class Date
{
public:Date(int year): _year(year){}
private:int _year;int _month = 1;int _day = 1;
};int main()
{Date d = 1999;return 0;
}
此处的Date d=1999就是隐式类型转换
然而explicit关键字可以阻止
构造对象时使用隐式类型转换
简直是一个非常卑鄙的关键字[doge]
使用方法:加在构造函数前
explicit Date(int year): _year(year){}