c++ 类和对象 —— 下 【复习总结】

1. 深入构造函数

1.1 函数体赋值

前文我们提到,创建对象时,编译器会调用构造函数给成员变量赋值。但这并不能称为对对象中成员变量的初始化。因为初始化只能初始化一次,但构造函数体内可以多次赋值 。构造函数体中语句只能称为赋初值

那么,成员变量初始化的地方在哪里?我们不得不引入一个知识:初始化列表

1.2 初始化列表

初始化列表:冒号开始 ,接着是逗号分隔成员列表 ,每个"成员变量"后跟一个放括号中的初始值或表达式

cpp 复制代码
class Date
{
private:
	int _year;
	int _month;
	int _day;

public:
	Date(int year, int month, int day)
		//初始列表
		:_year(year)
		,_month(month)
		,_day(day)

	   //函数体赋值
	   {}
};

注意事项:

  1. 每个成员变量在初始化列表最多出现一次(即只能初始化一次)

  2. 类中包含:a.引用成员变量 b.const成员变量 c. 自定义成员函数(且该类没有默认构造函数)

(a 和 b 是因为要求在定义时必须初始化;c 是因为会自动调用它的默认构造函数)

  1. 尽量使用初始化列表初始化,对于自定义类型成员变量,一定会先使用初始化列表初始化

  2. 成员变量在类中声明次序是其在初始化列表中的初始化顺序,和它在初始化列表的先后次序无关

cpp 复制代码
class A
{
private:
	int _a;
public:
	A(int a)
		: _a(a)
	{}
};

class B
{
private:
	A _ao;   //没有默认构造函数
	int& _ret; //引用
	const int _n; //const
public:
	B(int a, int ret)
		:_ao(a)
		,_ret(ret)
		,_n(10)
	{}
};

1.3 explicit关键字

对于接受单个参数的构造函数,还有类型转换的作用。

接受单个参数的构造函数:

  1. 构造函数只有一个参数

  2. 构造函数有多个参数,除第一个参数没默认值,其他参数都有默认值

3 .全缺省构造函数

但用explicit修饰构造函数,会禁止构造函数的隐式转换

cpp 复制代码
class Date
{
private:
	int _year;
	int _month;
	int _day;
public:
	//单参数构造函数,有类型转换的作用
	//用explicit修饰,禁止类型转换
	explicit Date(int year)
		:_year(year)
	{}

	//有两个缺省参数,相当于单个参数
	explicit Date(int year, int month=1, int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
		{}
};

2. static成员

声明为static的类成员为类的静态成员, 修饰成员变量称为静态成员变量;修饰成员函数称为静态成员函数。静态成员变量必须在类外初始化

特性:

  1. 静态成员为所有类对象共享,存放在静态区

  2. 静态成员变量必须在类外定义,类中只是声明,定义不加static关键字

  3. 静态成员用 类名::静态成员 或者 对象.静态成员 访问

  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

5.静态成员也是类的成员,受到访问限定符的限制

3. 友元

友元可以突破类封装的限制。但友元会增加耦合度,破坏封装,不宜多用

友元:友元函数友元类

3.1 友元函数

友元函数可以直接访问类的私有成员 ,它是定义在类外部 的普通函数,需要在类的内部声明 ,声明时要加friend关键字

注意事项:

  1. 友元函数不是类的成员函数,只是可以访问类的私有和保护成员

  2. 友元函数不能用const修饰

  3. 友元函数可以在类定义的任何位置声明,不受访问限定符的限制

  4. 一个函数可以是多个函数的友元函数

  5. 友元函数的调用和普通函数调用相同

适用场景:

cpp 复制代码
//如果想重载operator<<,但无法重载为类成员函数。
//this指针默认是第一个参数也就是左操作数了。
//但是实际使用中cout需要是第一个形参对象,所以要将operator << 重载成全局函数。
// 但类外没办法访问成员,此时就需要友元来解决。operator >> 同理
class Date
{
    friend ostream& operator<<(ostream& _cout, const Date& d);
    friend istream& operator>>(istream& _cin, Date& d);
public:
    Date(int year = 2025, 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;
}

3.2 友元类

友元类的所有成员函数都可以是另一个类的友元函数,可以访问另一个类的成员

注意事项:

  1. 友元关系单向,不具有交互性

  2. 友元关系不能传递

  3. 友元关系不能继承

cpp 复制代码
class Time
{
 //声明日期类为时间类的友元类,在日期类中可以直接访问Time类的私有成员变量
 friend class Date;
public:
    Time(int hour = 0, int minute = 0, int second = 0)
        : _hour(hour)
        , _minute(minute)
        , _second(second)
    {}

private:
    int _hour;
    int _minute;
    int _second;
};

class Date
{
public:
    Date(int year = 2025, int month = 1, int day = 1)
        :_year(year)
        , _month(month)
        , _day(day)
    {}

    void SetTimeOfDate(int hour, int minute, int second)
    {
        // 直接访问时间类私有的成员变量
        _t._hour = hour;
        _t._minute = minute;
        _t._second = second;
    }

private:
    int _year;
    int _month;
    int _day;

    Time _t;
};

4. 内部类

一个类定义在另一个类的内部,这个内部的类就叫内部类。

它不属于外部类,不能通过外部类的对象去访问内部类的成员(外部类对内部类没有任何超越的访问权限),**但内部类是外部类的友元类,**内部类可以通过外部类对象参数访问外部类中所有成员。

注意事项:

  1. 内部类可以定义在外部类的任意地方(如同友元)

  2. 内部类可以直接访问外部类的static成员,不需要外部类的对象/类名

  3. sizeof(外部类)= 外部类,相当于内部类不存储在外部类

cpp 复制代码
class A
{
private:
	static int a;
	int b;
public:
	// B是A的友元
	class B
	{
	public:
		void fun(const A& i)
		{
			//不用外部类的对象
			cout << a << endl;
			cout << i.b << endl;
		}
	};
};
int A::a = 1;
相关推荐
Leon_az几秒前
C++ 构造函数调用顺序以及什么是虚析构函数?为什么需要它?
c++
JANYI20183 分钟前
C语言中的双链表和单链表详细解释与实现
c语言·开发语言·windows
努力努力再努力wz5 分钟前
【C++深入系列】:模版详解(上)
java·c语言·开发语言·c++
慕容青峰18 分钟前
【蓝桥杯 2025 省 A 扫地机器人】题解
c++·算法·蓝桥杯·sublime text
Miao kristoff25 分钟前
开始放飞之先搞个VSCode
c++·vscode·编辑器
旋风小飞棍35 分钟前
spark和hadoop的区别与联系
大数据·开发语言·scala
joekl1 小时前
深度学习神经网络全连接笔记day1
笔记·深度学习·神经网络
bookish_2010_prj1 小时前
链式栈和线性栈
数据结构·c++·算法
我慢慢地也过来了1 小时前
servlet+jdbc+jsp实现增加操作
java·开发语言·servlet
凕雨1 小时前
Cesium学习笔记——dem/tif地形的分块与加载
前端·javascript·笔记·学习·arcgis·vue