创作不易,多多支持! !😘😘
前言
因为前面的构造函数还有些地方不够清晰,所以这里需要再继续补充一些
一 初始化列表
1.1认识初始化
对于默认的构造函数来说,我们都知道它是起到了初始化的操作,但是它对于内置类型是不做处理的,所以一般初始化都需要我们主动去写,不然就算一堆随机值。下面就来看看构造函数初始化的具体步骤
我们还是拿日期类来说明
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
Date()
{}
void Print()
{
cout << _year<<'-' << _month << '-' << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
d.Print();
return 0;
}
以上代码就写了一个构造函数,其作用什么都不干,对于打印的结果就是一堆随机值
那我们改成我们常用的形式看看如何
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
Date()
{
_year = 2024;
_month = 4;
_day = 27;
}
void Print()
{
cout << _year<<'-' << _month << '-' << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
d.Print();
return 0;
}
很显然输出的答案就发生了变化
说这么多其实就是想表达一个点,这并不是初始化而是赋值
因为初始化是在初始化列表实现的,函数体里只是赋值,所以这里要分清楚
对于真实性,我们可以调试来看看
从图中我们可以看到的是,在进入构造函数里时,所有值都已经初始化成了随机值,后面的仅仅只是对这些内置类型赋值而已.
而对于初始化,就是由初始化列表提供的,因为我们没有显示的写出初始化列表,所以编译器就自动给了随机值。
1.2为什么要写初始化列表
对于上面的认识,可能就会觉得,为啥要初始化,直接让编译器初始化为随机值,我们后面再来赋值不就好了,其实不然。
对于以下类型必须得初始化
int& a;//引用
const int b;//const 类型
A c;//没有默认构造的对象
以上类型必须得初始化,不然就会报错,所以就有初始化列表这个概念
所有的内置类型都需要经过初始化列表
对于上面三个类型,必须放在初始化列表进行初始化,不然就会报错。
1.3 初始化的形式
那么对于初始化列表的基本形式应该是这样的
class Date
{
public:
Date(int year, int month, int day): _year(year), _month(month), _day(day)
{}
private:
int _year;
int _month;
int _day;
};
那对于上面的样例,我们可以照虎画猫有
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A//A类
{
public:
A(int a):m(a)
{}
private:
int m;
};
class Date//日期类
{
public:
Date(A c,int& a):_a(a),_c(c),_b(10)
{
_year = 2024;
_month = 4;
_day = 27;
}
void Print()
{
cout << _year<<'-' << _month << '-' << _day << endl;
}
private:
int _year;
int _month;
int _day;
//必须初始化的类型
int& _a;
const int _b;
A _c;
};
int main()
{
A c(1);
int a = 0;
Date d(c,a);
return 0;
}
注意:
1.所有变量的初始化只进行一次,但是赋值可以多次
2.初始化列表初始化的顺序是按照声明的顺序初始化的
1.4 explicit 关键字
对于单个参数的构造函数而言
有下面三种情况
1. 构造函数只有一个参数2. 构造函数有多个参数,除第一个参数没有默认值外,其余参数都有默认值3. 全缺省构造函数
class Date
{
public:
explicit Date(int year,int month=7,int day=21)
{
_year = 2024;
_month = 4;
_day = 27;
}
void Print()
{
cout << _year<<'-' << _month << '-' << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024)
d1 = 2024;//这里其实发生了隐式类型转换
return 0;
}
上面的代码是编译不过的,因为加了一个 explicit,它是阻止类型转换的。
一个整数赋值给一个对象,那么这个整数先转换成相同类型的对象,然后再赋值。
这里注意,如果有多个参数,上面的就会报错。
二 Static关键字
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。
private:
int _year;
int _month;
static int _day;//声明
};
int Date::_day = 20;//初始化
其中我们还需要注意的是
1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
以上几点注意就行了,特别是第4点。
其实还有一个特例
private:
int _year;
int _month;
const static int _day;//如果加入一个const,那么就可以不在类外面初始化
};
这个只对int类型有效,对于其他类型都是无效的
用static修饰以后,那么这个成员就是所有类共有的,所以可以直接用类名访问。
三 友元
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多
用。
友元分为:友元函数和友元类
3.1友元函数
友元函数就是在函数名前加上friend
下面给出一个实例进行说明
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& _cout, const Date& d);
friend istream& operator>>(istream& _cin, Date& d);
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
istream& operator>>(istream& _cin, Date& d)
{
_cin >> d._year;
_cin >> d._month;
_cin >> d._day;
return _cin;
}
int main()
{
Date d;
cin >> d;
cout << d << endl;
return 0;
}
这段代码是对输入输出流的操作符进行了重载,使之可以输入对象,而不单单是内置类型
,那为什么要把这两个函数定义为友元呢?
如果不定义为友元,那我们就得把这两个函数放到类里面去才能访问到私有的成员变量,那么又有一个问题就来了。
友元函数可访问类的私有和保护成员,但不是类的成员函数
友元函数不能用const修饰
友元函数可以在类定义的任何地方声明,不受类访问限定符限制
一个函数可以是多个类的友元函数
友元函数的调用与普通函数的调用原理相同
友员函数不是成员函数,所以不能被const修饰,这一点要注意。
3.2 友元类
1.友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
2.友元关系是单向的,不具有交换性。
4.友元关系不能传递
如果B是A的友元,C是B的友元,则不能说明C时A的友元。
定义了友元类,比如B是A的友元,那么B可以访问A的所有成员,但是A不能访问B的成员,比较自私
内部类
如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
其实就是跟友元类是差不多的,只不过友元类打破了封装性,但是内部类使封装更加好。
以上就是关于对构造函数的一些补充还有其他知识点的说明,如果看到这里对你有帮助,那支持一些吧😍😍😍