目录
前言
前面我们通过介绍C++的六个默认成员函数,从而实现了日期类,但对于C++的类和对象而言,还有一些零碎的知识,比如:初始化列表,匿名对象,友元等问题,因此,本篇文章我将从以上几个方面再谈构造函数,由浅入深介绍上述知识点。
初始化列表
概念:是一种以逗号开始,冒号分隔的数据成员列表,每个成员变量后跟一个放在括号中的初始值或表达式。
那么这个初始化列表与构造函数有什么关系呢?实际上,初始化列表是跟在构造函数后面的,以日期类为例:
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{
}
private:
int _year=1900;
int _month=1;
int _day=1;
};
如上所视,构造函数下面的就是初始化列表。
那么此时我们会有一个问题,为什么C++要引入初始化列表呢?初始化列表有什么用呢?我们以MyQueue为例,如果我们要使用Stack来实现MyQueue的功能,此时如果Stack没有默认构造,那么MyQueue也无法生成默认构造,因此为了解决这个问题,我们才引入了初始化列表,所以初始化列表的功能实际上是为了初始化成员变量而存在。
那么,初始化列表是如何完成初始化呢?我们在前面知道,C++11规定了成员变量在定义的时候可以给缺省值,那么这个语法是如何实现的呢?实际上这个缺省值是给初始化列表的,因此我们可以知道:初始化列表本质是成员定义的地方。
注意:
1.每个成员变量在初始化列表中只能出现一次,即:只能初始化一次
2.当类中包含const成员变量,引用成员变量,自定义类型成员变量(且没有默认构造函数)这三种只能在初始化列表位置初始化
3.尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定使用初始化列表初始化(初始化列表不管写不写,每个成员变量都会走一遍),实践中,先走初始化列表再走函数体
4.成员变量的声明次序就是在初始化列表中初始化顺序,原因在于:对象在内存中是按声明次序存放的
explicit关键字
在介绍explicit关键字之前,我们首先介绍一下隐式类型转换,当我们要将内置类型转换为自定义类型时会构造临时对象,这个临时对象再拷贝复制给自定义对象,当编译遇到连续的构造+拷贝构造则会直接优化为直接构造。那么explicit关键字与隐式类型转换有什么关系呢?实际上,explicit修饰构造函数能够禁止隐式类型转换。
static成员
概念:static修饰的类成员被称为类的静态成员;修饰成员变量称为静态成员变量;修饰成员函数被称为静态成员函数。其中对于静态成员变量需要在类外初始化。
特性:
1.static修饰的成员存在静态区,不存在对象中,在计算成员变量大小时不考虑
2.静态成员变量在定义的时候不能给缺省值,因为缺省值是给初始化列表,其初始化需要在类外初始化
3.静态成员函数不含隐藏的this指针,不能访问任何非静态成员
4.静态成员也是类的成员,受public,private,protected限制
class A
{
public:
A()
{
++_a;
}
static int Fun()
{
//只能访问静态成员
return _a;
}
private:
//静态成员变量
static int _a;
};
//静态成员变量在类外定义
int A::_a = 0;
友元
前面我们讨论过一个问题,当我们把函数重载为全局时无法访问私有,那么如何解决这个问题呢?我们可以提供这个成员的Get和Set,重载为成员函数,以及友元。
因此可以这么说,友元提供了一种突破封装的方式,其可以分为友元类和友元函数
友元函数
友元函数可以直接访问私有成员,它是定义在类外的普通函数,不属于任何类,当我们要调用时需要在类的内部声明,声明时需要加上friend关键字
以前面我们写的重载流插入和流提取函数为例:
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
Date(int year, int month, int day)
:_year(year)
, _month(day)
, _day(day)
{}
private:
int _year = 1900;
int _month = 1;
int _day = 1;
};
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << endl;
return out;
}
istream& operator>>(istream& in, Date& d)
{
cout << "请依次输入年月日";
in >> d._year >> d._month >> d._day;
return in;
}
注意:
1.友元函数可以访问私有和保护成员,但不是类的成员函数
2.友元函数不能使用const修饰
3.友元函数可以在类的任何位置声明,不受类访问限定符限制
4.一个函数可以是多个类的友元函数
5.友元函数的调用与普通函数调用原理相同
友元类
注意
1.友元关系是单向的,不具有交换性和传递性
2.友元关系不能继承
3.友元类中的所有成员函数都是另一个类的友元函数,都可以访问另一个类的私有成员
class A
{
friend class B;
public:
A(int a=0,int b=0,int c=0)
:_a(a)
,_b(b)
,_c(c)
{}
int Fun()
{}
private:
int _a;
int _b;
int _c;
};
class B
{
public:
void SetofA(int a, int b, int c)
{
_g._a = a;
_g._b = b;
_g._c = c;
}
private:
int _d;
int _e;
int _f;
A _g;
};
如上述代码,我们创建了两个类A,B,在A中声明B是A的友元,那么在B中就可以访问A,通俗讲,B是A的朋友,那么B就可以去A的家里玩耍,但是A并没有把B当成朋友,所以A并不能去B的家里,也就是说,B可以访问A,但A并不能访问B
内部类
概念:如果一个类定义在另一个类的内部,这个类就叫内部类
注意:
1.内部类不属于外部,因此外部类不能访问内部类,但是内部类可以访问外部类,即:内部类天生就是外部类的友元
2.内部类可以定义在public,private,protected
3.内部类可以直接访问外部类的static成员
总结
本篇文章补充了C++中类和对象的方面的内容,分别介绍了初始化列表、隐式类型转换和explicit关键字、stctic成员、友元等相关知识,同时感谢您能在百忙之中抽空看完我的文章,受限于博主的知识水平,可能会有所纰漏,欢迎各位指正。如果本篇文章对您有所帮助的话,希望您能够点赞评论关注加转发,您的支持就是对我创作的最大鼓励。