C++初阶第六篇——类和对象(下)(初始化列表+explicit关键字+static成员+友元+内部类)
Posted 呆呆兽学编程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++初阶第六篇——类和对象(下)(初始化列表+explicit关键字+static成员+友元+内部类)相关的知识,希望对你有一定的参考价值。
⭐️今天我要和大家分享C++中类和对象中的最后一篇,来做一个补充。
⭐️博客代码已上传至gitee:https://gitee.com/byte-binxin/cpp-class-code
目录
🌏构造函数中的初始化列表
初始化列表: 以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
class
public:
Date(int year, int month, int day)// 成员变量定义处 给变量开空间
: _year(year)
, _month(month)
, _day(day)
private:
// 成员变量声明处
int _year;
int _month;
int _day;
;
注意:
- 每个成员变量只能在初始化列表中出现一次
- 类中包含定义时必须初始化的成员时,必须使用初始化列表
- const成员变量(常量)
- 引用成员变量(引用必须在定义时初始化)
- 无默认构造函数(无参、全缺省和编译器给的默认构造函数)的自定义类型成员变量
class AA
public:
AA(int a)// AA类无默认构造函数,必须使用初始化列表
_a = a;
private:
int _a;
;
class Date
Date(int year = 1, int month = 1, int day = 1, int i = 10)
:_a(10)
,_ref(i)
,_aa(10)
_year = year;
_month = month;
_day = day;
void Print()
cout << _year << "-" << _month << "-" << _day << endl;
private:
// 成员变量声明的地方 还未申请空间
int _year;
int _month;
int _day;
// 以下三个成员变量都是必须在定义时初始化
const int _a;
int _ref;
AA _aa;
;
我们一般尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
一个小问题
看下面这串代码运行结果是什么?
class A public: A(int a) :_a2(a) ,_a1(_a2) void Print() cout << _a1 << " " << _a2 << endl; private: int _a1; int _a2; ; int main() A a(10); a.Print(); return 0;
代码运行结果如下:
解释:
成员变量在初始化列表的初始化顺序与声明顺序有关,和在初始化列表的先后顺序无关。
代码中是 _a1 声明顺序先于 _a2 ,所以 _a2 先给 _a1 赋值,因为此时 _a2 里面放的是随机值,所以 _a1 是随机值,然后10赋值给 _a2 ,所以 _a2 就是10.
🌏explicit关键字
在C语言中,有一个隐式类型转换的概念,相近类型,意义相似的类型可以发生隐式类型转换。例如int和double两个类型都是表示大小的,所以可以发生。那么,在自定义类型中是否可以发生这中转换吗?
先看下面一串代码:
class Date
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
private:
int _year;
int _month :
int _day;
;
int main()
Date d1 = 2022, 1, 21 ;
return 0;
其中,Date d1 = 2022, 1, 21 ; 这里其实是编译器先用 2022, 1, 21 构造一个匿名对象,然后把这个对象给d1赋值,因为两次构造是连续的,所以两个动作会被编译器优化为一个构造,两次都是直接构造,但是意义还是不同的。
如果我们不想这种隐式类型转换发生,我们一般在构造函数前面加一个explicit的关键字。
explicit Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
🌏static成员
概念: 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化。
特性:
- 静态成员属于整个类,且不占类的大小
- 静态成员变量是在类内声明,类外定义的
- 静态成员可以直接通过::指定类域来访问
- 静态成员函数中没有this指针,不能访问非静态的成员
我们实现一个类,计算该程序创建了多少个对象
class Date
public:
Date(int year = 1, int month = 1, int day = 1)
_sCount++;
_year = year;
_month = month;
_day = day;
// 静态成员函数 无this指针,可以直接用::指定类域访问
// 只能访问静态成员变量和函数
static int GetCount()
return _sCount;
void Print()
cout << _year << "-" << _month << "-" << _day << endl;
private:
// 成员变量声明的地方
int _year;
int _month;
int _day;
// 静态成员变量属于整个类(所有类)生命周期在整个程序运行期间
// 可以直接用::指定类域访问
static int _sCount;// 类内声明,类外初始化定义
;
// 静态必须要在类外初始化定义
int Date::_sCount = 0;
🌏C++11中新的初始化方式
class Date
public:
void Print()
cout << _year << "-" << _month << "-" << _day << endl;
private:
// 成员变量声明的地方
// 注意,这里不是定义,而是声明,在声明是给缺省值
int _year = 1;
int _month = 1;
int _day = 1;
static int _sCount;// 静态成员变量不能像上面一样
;
// 静态必须要在类外初始化定义
int Date::_sCount = 0;
🌏友元
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
💎友元函数
我们实现一个在类外实现operator<< 和 **operator>>**重载运算符函数。如果放在类内的话,那么this指针就是第一个默认的参数,所以我们选择在类外实现,可以调换参数的顺序。
class Date
// 友元函数
// 不能用const修饰 const修饰的是非静态的成员函数 一个类可以是很多函数的友元
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
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;
;
// 全局
ostream& operator<<(ostream& out, const Date& d)
out << d._year << "-" << d._month << "-" << d._day << endl;
return out;
istream& operator>>(istream& in, Date& d)
in >> d._year >> d._month >> d._day;
return in;
特性:
- 不能用const修饰
- const修饰的是非静态的成员函数
- 一个类可以是很多函数的友元
💎友元类
友元类,就是让一个类称为另一个类的友元,这样这个类就可以访问另一个类中的所有私有属性。
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;
private:
int _year;
int _month;
int _day;
;
class Time
// 友元类
// Date类是Time类的友元 Date可以访问Time的私有成员 单向 不能传递
friend class Date;
public:
Time(int hour, int minute, int second)
:_hour(hour)
, _minute(minute)
, _second(second)
private:
int _hour;
int _minute;
int _second;
;
🌏内部类
概念: 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。
特性:
- 外部类天生就是内部类的友元类,内部类具有访问外部类私有属性的权限,但外部类却没有访问内部类的私有属性的权限
- 内部类只是受外部类的类域的限制,内部类并不属于外部类,也就是sizeof(外部类)=内部类
class A
private:
static int _a;
int _b;
public:
// 内部类
// B天生就是A的友元 B可以访问A的私有成员,但是A不可以访问B的私有
// sizeof(A) = 4 A中成员变量b a属于整个类,不占对象的大小 内部类B和在全局定义的基本一致,知识受A类域的限制
class B
public:
void f()
private:
int _a;
;
;
int A::_a = 10;
🌐总结
C++的类和对象全部内容就介绍到这里了,喜欢的话,欢迎点赞支持~
以上是关于C++初阶第六篇——类和对象(下)(初始化列表+explicit关键字+static成员+友元+内部类)的主要内容,如果未能解决你的问题,请参考以下文章
数据结构初阶第六篇——初识二叉树(二叉树的基本性质+二叉树的顺序存储结构及实现)
C++初阶第五篇——类和对象(中)(构造函数+析构函数+拷贝构造函数+赋值操作符重载)
C++初阶第一篇——初始C++(命名空间+缺省参数+函数重载)