0%
boxmoe_header_banner_img

加载中

类和对象(下)


avatar
mizuki 2026年6月5日 2026年6月6日 69

引言

这将是类和对象的最后一篇文章,相信经 过最后一篇文章的学习,一定能够加深你对类和对象的理解

1.再探构造函数

  • 1.1初始化列表

在构造函数的函数名后接一个引号“ : ”,然后写需要初始化的成员对象,在成员对象后接括号,括号内是对应成员初始化的值,每个成员的初始化之间用逗号“ , ”相隔,下面将给出一个例子

class A
{
public:
	A(int a, int b) : _a(a),
		_b(b)
	{

	}
private:
	int _a;
	int _b;
};
  • 1.2特点

1.每个成员只能初始化一次

2.每个成员对象都要走初始化列表

3.const类型,引用,和没有默认构造的自定义类型对象只能够在初始化列表中定义,否则会报错

4.尽量使用初始化列表初始化

5.初始化列表初始化的顺序是按照声明的顺序初始化的,而不是定义,给出一个例子

class A
{
public:
	A(int a, int b) : _b(b),
		_a(a)
	{

	}
private:
	int _a;
	int _b;
};

这里初始化的顺序是a->b,而不是b->a

6.构造函数中可以给缺省值,成员对象也可以给缺省值

2.隐式类型转换

1.C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数,多参数的要用{}

2.如果在构造函数前加explict,就可以防止隐式类型转换

3.类类型之间也支持隐式类型转换,但需要相对应的构造函数

这里给出隐式类型转化的几个例子

class A
{
public:
	A(int a, int b) : _a(a),
		_b(b)
	{

	}
	void Print()
	{
		cout << _a << " " << _b << endl;
	}

	int Get() const
	{
		return _a + _b;
	}
private:
	int _a;
	int _b;
};

class B
{
public:
	B(const A& a) : _a(a.Get())
	{

	}
	void Print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};

int main()
{
	//普通隐式类型转换
	A a1 = { 1, 2 };
	a1.Print();

	//类类型的隐式类型转换
	B b1 = a1;
	b1.Print();

	return 0;
}

要注意到的是这里的{}初始化是利用了普通隐式类型转换,而b1 = a1用到的则是类类型的转换,这里给出程序运行的结果,是可以看到a1和b1都是成功初始化了的

3.static成员

  • 3.1 特点

1.静态成员必须在类外初始化

2.static成员为所有类对象共享,不单属于某一个类,放在静态区

3.静态函数无this指针,不能够访问非静态的对象

  • 3.2 例子

这里给出static成员的使用样例

class C
{
public:
	C(int b): _b(b)
	{}

	void Aadd()
	{
		_a++;
	}

	void APrint()
	{
		cout << "_a = " << _a << " ";
		cout << "_b = " << _b << endl;
	}

	static void APrint2()
	{
		cout << "_a = " << _a << " ";
		cout << "_b = " << _b << endl;
	}

private:
	static int _a;
	int _b = 3;
};

//在类外进行初始化
int C::_a = 0;

int main()
{
	C a1(2);
	C a2(3);

	a1.APrint();
	a2.APrint();

	/*利用a1对静态_a对象++,a2中的_a也会改变*/
	a1.Aadd();
	a2.APrint();
	return 0;
}

首先我们注意到APrint2是静态函数,是无法直接调用_b这个对象的,这里会给出报错:

再看运行结果,利用a1对静态_a对象++,a2中的_a也会改变,因此运行结果如下:

4.友元

  • 4.1 定义和分类

为了突破访问限定符,分为友元函数和友元类,基本格式为:friend class A / void A()

  • 4.2 特点

1.可以访问友元类的私有和保护成员

2.可以在类的任何位置声明,仅仅只是一个声明

3.一个函数可以成为多个类的友元,类也是如此

4.对于友元类函数,将B放在A中作为友元类,那B中就可以访问A的私有和保护成员,这里给出最经典的例子,关于日期类<<和>>的重载:

5.友元类的关系是单向的,也不能够传递,这里给出一个例子:

class D
{
	friend class E;
private:
	int _d;
};

class E
{
	friend class F;
private:
	int _e;
};

class F
{
public:
	void PrintD(D d, E e)
	{
		cout << d._d << endl;
	}
private:
	int _f;
};

这里演示的是友元是不可以传递的,由代码可知,F是E的友元类,E是D的友元类,但是F不是D的友元类,是无法调用到D的私有成员的,如图所示:

class E
{
private:
	int _e;
};

class F
{
	friend class E;
public:
	void PrintD(E e)
	{
		cout << e._e << endl;
	}
private:
	int _f;
};

这里演示的是友元是单向的,E是F的友元类,但是F是无法调用到E的私有成员的,如图所示:

5.内部类

  • 5.1 定义

一个类定义在另一个类的内部,这个类是一个独立的类,仅仅只是受到了类域的限制

  • 5.2 特点

1.默认内部类是外部类的友元

2.与友元类相同,外部类不能直接调用内部类的私有和保护成员,友元关系是单向的,如图:

class H
{
	class h
	{
	public:
		void Print(H a)
		{
			cout << a._H;
		}
	private:
		int _h = 2;
	};

public:
	void Print(h a)
	{
		cout << a._h;
	}
private:
	int _H = 1;
};

6.匿名对象

特点是一次性使用,经常用在传参,调用函数中,匿名对象的声明周期只有这一行,下面给出使用的例子:

class L
{
public:
	L(int l): _l(l)
	{}
	int Get()
	{
		return _l;
	}
private:
	int _l;
};

int main()
{
	cout << L(3).Get() << endl;
	return 0;
}

运行结果如下:

7.对象拷贝的编译器优化

  • 7.1 定义

C++标准允许编译器在某些情况下省略对象的拷贝/移动操作,即使拷贝/移动构造函数有副作用。这是C++中最重要的拷贝优化机制。

  • 7.2 特点

1.可能只产生临时变量,不产生拷贝对象

2.每个编译器的优化不同

  • 7.3

因为这部分较为复杂,在此不过多讲解,想详细了解的可以自己去查询资料

总结

至此,类和对象的内容就这样结束了,其实这篇文章我已经写了两遍了,因为虚拟机更新忘记备份了,因此大家写博客的时候一定要勤备份啊!

上一次更新已经跑远了✨ 计算中...
(‾◡◝) 本内容里的一些消息,可能已经跟不上时间啦~


评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字

插入代码
小园得志

北京时间 (Asia/Shanghai)

后退
前进
刷新
复制
粘贴
全选
删除
返回首页
0%
目录
顶部
底部
📖 文章导读