自学内容网 自学内容网

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成员、友元等相关知识,同时感谢您能在百忙之中抽空看完我的文章,受限于博主的知识水平,可能会有所纰漏,欢迎各位指正。如果本篇文章对您有所帮助的话,希望您能够点赞评论关注加转发,您的支持就是对我创作的最大鼓励。


原文地址:https://blog.csdn.net/f040731_007/article/details/142401223

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!