C++从入门到入土(五)——再谈构造函数
目录
前言
初始化列表
explicit关键字
static成员
友元
友元函数
友元类
内部类
总结
前言
前面我们通过介绍C++的六个默认成员函数,从而实现了日期类,但对于C++的类和对象而言,还有一些零碎的知识,比如:初始化列表,匿名对象,友元等问题,因此,本篇文章我将从以上几个方面再谈构造函数,由浅入深介绍上述知识点。
C++从入门到入土(四)--日期类的实现
C++从入门到入土(三)--6个默认成员函数
初始化列表
概念:是一种以逗号开始,冒号分隔的数据成员列表,每个成员变量后跟一个放在括号中的初始值或表达式。
那么这个初始化列表与构造函数有什么关系呢?实际上,初始化列表是跟在构造函数后面的,以日期类为例:
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成员、友元等相关知识,同时感谢您能在百忙之中抽空看完我的文章,受限于博主的知识水平,可能会有所纰漏,欢迎各位指正。如果本篇文章对您有所帮助的话,希望您能够点赞评论关注加转发,您的支持就是对我创作的最大鼓励。