【C++】类和对象(三)

【C++】类和对象(三)

一.const成员:让对象更安全

1.const关键字的作用

C++中const用来表示"常量"的意思,用来修饰变量,表示这个变量的值不可被修改。

2.const修饰普通变量

cpp 复制代码
const int a=10;

此时表示"a"是常量,不可修改。

另外,const修饰的变量必须在定义时初始化,否则就会报错。

例如:

3.const修饰类成员变量

const修饰的类成员变量必须在初始化列表初始化,并且不能在构造函数体内赋值。

例如如下两种写法都是错的:

4.const修饰类成员函数

语法:

返回值 函数名(参数)const

{

...函数体

}

作用:const修饰的成员函数保证不会修改函数内对象的成员变量。

例如:

如果想让成员变量可以被const成员函数修改,可以使用"mutable"修饰变量。

例如:

使用:const对象只能调用const成员函数,非const对象可以调用任意成员函数。

例如:

cpp 复制代码
class Test
{
public:
	Test(int x)
		:a(x)
	{}
	void Print1()
	{
		cout << "a:" << a << endl;
	}
	void Print2() const
	{
		cout << "a:" << a << endl;
	}

private:
	int a;
};

int main()
{
	Test t1(10);
	const Test t2(20);

	t1.Print1();
	t1.Print2();

	t2.Print1();//错误,const对象只能调用const成员函数
	t2.Print2();


	return 0;
}

5.const成员函数和非const成员函数重载

同名const成员函数和非const成员函数可以重载,实现const对象和非const对象的不同行为。

例如:

cpp 复制代码
class Test
{
public:
	Test(int x)
		:a(x)
	{
	}
	void Print()
	{
		cout<<"普通成员函数 " << "a:" << a << endl;
	}
	void Print() const
	{
		cout << "const成员函数 " << "a:" << a << endl;
	}

private:
	int a;
};

int main()
{
	Test t1(10);
	const Test t2(20);

	t1.Print();	//调用普通成员函数

	t2.Print();	//调用const成员函数

	return 0;
}

代码运行结果为:

二.static静态成员:类级共享与生命周期管理

1.什么是static静态成员

在C++中,"static"可以修饰类中的成员变量和成员函数,被"static"修饰的成员就被称作"静态成员变量","静态成员函数"。

2.static静态成员作用

在类中,被static修饰的成员表示该成员脱离对象实例,成为类本身的属性。

3.静态成员变量

被"static"修饰的成员变量就叫静态成员变量。

  • 特性:
    ① 所有对象共享同一份静态成员变量。
    ② 必须在类外定义并初始化(除非是const static整型),因为它属于整个类,存储在静态区。
    ③ 不占用对象的内存空间。
  • 示例:
    比如我们定义了一个学生类,想统计创建了多少个学生类对象,如果使用普通成员变量,比如
cpp 复制代码
class Student
{
public:
	Student()
	{
		_count++;
	}
private:
	int _count;
};

这种是错误的写法,因为这样写每个学生对象都会创建一个自己的_count变量,无法统计总数。

此时就可以使用"static"关键字。

cpp 复制代码
class Student
{
public:
	Student()
	{
		_count++;
	}
	static  int _count;//只是声明
};

int Student::_count = 0;//类外定义并初始化

int main()
{
	Student s1;
	Student s2;
	Student s3;

	cout << "学生类对象个数为:" << Student::_count;
	return 0;
}

代码运行结果为:

4.静态成员函数

被"static"修饰的成员函数就叫静态成员函数。

  • 特性:
    ① 无this指针,所以不能访问非静态成员变量/函数。
    ② 可通过类名或对象名调用(推荐类名::函数名)
    ③ 静态成员函数不能同时被const修饰,因为const修饰本质是修饰this指针,但静态成员函数不含this指针。
  • 示例:
cpp 复制代码
class Student
{
public:
	Student()
	{
		_count++;
	}

	static void PrintCount()
	{
		cout << "学生类对象个数为:" << _count << endl;
	}
private:
	static  int _count;//只是声明
};

int Student::_count = 0;//类外定义并初始化

int main()
{
	Student s1;
	Student s2;
	Student s3;

	Student::PrintCount();//通过类名::函数名调用

	return 0;
}

代码运行结果为:

三.友元:突破封装的特权机制

1.为什么需要友元

C++中类的封装限制了私有成员不能在类外直接访问。

例如:

cpp 复制代码
class Student
{
public:
	Student(int age)
		:_age(age)
	{}

private:
	int _age;
};

如果在类外访问,是错误的

Student s(18);

s.age = 19;//错误,私有成员类外不可直接访问

但有些情况下,类外需要访问类的私有成员,此时就需要使用友元突破封装的限制。

2.友元的概念

友元可以分为友元函数和友元类,友元可以访问当前类的私有成员和保护成员。

3.友元函数

  • 定义:

    友元函数不是类的成员函数,它是在类外定义的普通函数,但需要在类内使用"friend"声明。

  • 特点:

    ① 可以访问类的私有成员和保护成员。

    ② 没有this指针(因为不是类的成员)。

    ③ 友元函数声明可以放在类的任何地方(无论放在 private、protected 还是 public,效果都一样)。

    ④ 一个函数可以是多个类的友元函数。

例如定义一个学生类和打印学生信息的友元函数:

cpp 复制代码
class Student
{
	friend void Print(const Student& s);//友元函数声明
public:
	Student(string name,int age)
		:_name(name),
		_age(age)
	{}

private:
	string _name;
	int _age;
};

//类外定义友元函数
void Print(const Student& s)//打印学生信息
{
	cout << "学生信息为:" << s._name << " " << s._age << "岁" << endl;
}
int main()
{
	Student s("张三",18);
	Print(s);

	return 0;
}

代码运行结果为:

4.友元类

  • 定义:
    一个类被声明另一个类用"friend"关键字声明,那么这个类就是另一个类的友元类。
  • 特性:
    ① 友元类的所有成员函数都可以访问另一个类的私有成员和保护成员。
    ② 友元类的友元关系是单向的(A是B的友元类,B不一定是A的友元类)。
    ③ 友元关系不能继承(父类的友元不一定是子类的友元)。
    ④ 友元关系不能传递(某个类的友元的友元不一定是它的友元,比如你朋友的朋友不一定是你的朋友)。
    示例代码:
cpp 复制代码
class Student
{
	friend class Teacher;
public:
	Student(string name,int age)
		:_name(name),
		_age(age)
	{}

private:
	string _name;
	int _age;
};

class Teacher
{
public:
	void PrintStudent(const class Student& s)
	{
		cout << "学生信息为:" << s._name << " " << s._age << "岁" << endl;
	}
};

int main()
{
	Student s("张三",18);
	Teacher t;
	
	t.PrintStudent(s);

	return 0;
}

代码运行结果为:

感谢阅读!

相关推荐
Zklys1 小时前
Cmake的学习笔记step1
c++·笔记·学习
右耳朵猫AI1 小时前
Java & JVM技术周刊 2026年第19周
java·开发语言·jvm
zincsweet1 小时前
C++ 实现进程池:主从架构、管道通信与任务调度
linux·c++
han_hanker1 小时前
Java 对象序列化
java·开发语言
zhojiew1 小时前
通过Toxiproxy从原理到实践理解混沌工程
开发语言·php
雪之下雪乃的代码日记1 小时前
认识Java中集合框架
java·开发语言·笔记
草莓熊Lotso1 小时前
【CMake】静态库的编译、链接与引用全解析
linux·c语言·数据库·c++·软件工程·cmake
少司府1 小时前
C++进阶:继承
c语言·开发语言·c++·继承·组合·虚继承
郝学胜-神的一滴1 小时前
CMake 012:Linux 下动态库与可执行程序的单文件构建
linux·服务器·开发语言·c++·软件构建·cmake