C++学习笔记(3)——封装

本文围绕C++面向对象类的封装展开,介绍了C++中struct和class的区别,以及封装的访问权限。还详细阐述了构造函数和析构函数的特点、分类、调用规则,深拷贝与浅拷贝问题及解决方法。此外,涉及初始化列表、静态成员、单例模式等内容,对C++面向对象编程有重要指导意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.面向对象类的封装

1.封装

1、C语言的封装
1.1、缺陷 将属性和行为分离
2、C++语言的封装
2.1、将属性和行为作为一个整体,来表现生活中的事物
2.2、将属性和行为 加以权限控制
3、访问权限
3.1、公共权限 public 类内 类外 都可以访问
3.2、私有权限 private 类内可以访问 类外不可以访问
3.3、保护权限 protected 类内可以访问 类外不可以访问
4、class 默认权限 私有权限 而 struct默认权限是 公共权限
5、尽量将成员属性设置为私有
5.1、自己可以控制读写权限
5.2、可以对设置内容 加有效性验证

C++中struct和class的区别

1.相同点
两者都拥有成员函数、公有和私有部分
任何可以使用class完成的工作,同样可以使用struct完成
2.不同点
两者中如果不对成员不指定公私有,struct默认是公有的,class则默认是私有的
class默认是private继承,而struct模式是public继承

在C++中,class和struct做类型定义是只有两点区别:

1.默认继承权限不同,class继承默认是private继承,⽽struct默认是public继承
2.class还可⽤于定义模板参数,像typename,但是关键字struct不能同于定义模板参数 C++保留struct关键
字,原因
3.保证与C语⾔的向下兼容性,C++必须提供⼀个struct
4.C++中的struct定义必须百分百地保证与C语⾔中的struct的向下兼容性,把C++中的最基本的对象单元规定为
class⽽不是struct,就是为了避免各种兼容性要求的限制
5.对struct定义的扩展使C语⾔的代码能够更容易的被移植到C++中

引申:C++和C的struct区别

1.C语言中:struct是用户自定义数据类型(UDT);C++中struct是抽象数据类型(ADT),支持成员函
数的定义,(C++中的struct能继承,能实现多态)
2.C中struct是没有权限的设置的,且struct中只能是一些变量的集合体,可以封装数据却不可以隐藏数
据,而且成员不可以是函数
3.C++中,struct增加了访问权限,且可以和类一样有成员函数,成员默认访问说明符为public(为了与
C兼容)
4.struct作为类的一种特例是用来自定义数据结构的。一个结构标记声明后,在C中必须在结构标记前加
上struct,才能做结构类型名(除:typedef struct class{};);C++中结构体标记(结构体名)可以直接
作为结构体类型名使用,此外结构体struct在C++中被当作类的一种特例

访问权限

public 公共权限 成员 类内 类外 都可以访问
private 私有权限 成员 类内 可以访问 类外 不可以访问 儿子不可以访问父亲的private权限内容protected 保护权限 成员 类内 可以访问 类外 不可以访问 儿子可以访问父亲的protected权限内容

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

struct  Person
{
	//公共权限
public:
	char name[64];
	int age;

	void PersonEat()
	{
		printf("%s在吃人饭\n", name);
	}
};

struct Dog
{
	//公共权限
public:
	char name[64];
	int age;
	void DogEat()
	{
		printf("%s在吃狗粮\n", name);
	}
};

//C++封装 理念:  将属性和行为作为一个整体,来表现生活中的事物
//第二次理念: 将属性和行为  加以权限控制

void test01()
{
	struct Person p;
	strcpy(p.name, "老王");
	p.PersonEat();
	//p.DogEat();
}

//struct和class 区别?
//class 默认权限  私有权限  而 struct默认权限是 公共权限
//访问权限
// public  公共权限    成员 类内  类外 都可以访问	 
// private 私有权限    成员 类内  可以访问  类外  不可以访问  儿子不可以访问父亲的private权限内容
// protected 保护权限  成员 类内  可以访问  类外  不可以访问  儿子可以访问父亲的protected权限内容

class Person2
{
public:
	string m_Name; //公共权限

protected:
	string m_Car;  //保护权限

private:
	int  m_pwd;  //私有权限

public:
	void func()
	{
		m_Name = "张三";
		m_Car = "拖拉机";
		m_pwd = 123456;
	}
};

void test02()
{
	Person2 p;
	p.m_Name = "李四"; //公共权限  类外可以访问
//	p.m_Car = "劳斯莱斯"; //保护权限  类外访问不到
//	p.m_pwd = 123; //私有权限  类外不可以访问
}

int main() {
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
class Person
{
public:
	//设置姓名
	void setName(string name)
	{
		m_Name = name;
	}
	//获取姓名
	string getName()
	{
		return m_Name;
	}

	//获取年龄
	int getAge()
	{
		return m_Age;
	}

	//设置年龄
	void setAge(int age)
	{
		if (age < 0 || age > 150)
		{
			cout << "你这个老妖精" << endl;
			return;
		}
		m_Age = age;
	}

	//设置情人
	void setLover(string lover)
	{
		m_Lover = lover;
	}

private:
	string m_Name;  //姓名  可读可写
	int m_Age = 18;      //年龄  可读 可写(0 ~ 150之间)
	string m_Lover; //情人  只写
};

void test01()
{
	Person p;
	//可以将char * 隐式类型转换为 string
	p.setName("张三");
	cout << "姓名: " << p.getName() << endl;

	//获取年龄
	p.setAge(100);
	cout << "年龄: " << p.getAge() << endl;

	//设置情人
	p.setLover("苍井");

	//cout << "张三情人是:"<< p.m_Lover <<endl; //情人是只写权限  外部访问不到

}

//将成员属性都设置为私有好处:自己可以控制读写权限
//可以对设置内容 加有效性验证
int main() {
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

2.构造函数和析构函数

1.构造函数
1.1//没有返回值 不用写void
1.2//函数名 与 类名相同
1.3//可以有参数 ,可以发生重载
1.4//构造函数 由编译器自动调用一次 无须手动调用
2.析构函数
2.1//没有返回值 不用写void
2.2函数名 与类名相同 函数名前 加 ~
2.3不可以有参数 ,不可以发生重载
2.4析构函数 也是由编译器自动调用一次,无须手动调用

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person
{
public: //构造和析构必须要声明在全局作用域

	//构造函数
	//没有返回值  不用写void
	//函数名 与 类名相同
	//可以有参数  ,可以发生重载
	//构造函数 由编译器自动调用一次 无须手动调用
	Person()
	{
		cout << "Person的构造函数调用" << endl;
	}
	
	//析构函数
	//没有返回值   不用写void
	//函数名 与类名相同  函数名前 加 ~
	//不可以有参数 ,不可以发生重载
	//析构函数 也是由编译器自动调用一次,无须手动调用
	~Person()
	{
		cout << "Person的析构函数调用" << endl;
	}
};

void test01()
{
	Person p;
}

int main(){
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

3.构造函数的分类和调用

1.分类
1.1按照参数分类: 有参 无参(默认)
1.2按照类型分类: 普通 拷贝构造 ( const Person & p )
2.调用
2.1括号法
2.2显示法
2.3隐式法
3.注意事项
3.1不要用括号法 调用无参构造函数 Person p3(); 编译器认为代码是函数的声明
3.2不要用拷贝构造函数 初始化 匿名对象 Person(p3); 编译器认为 Person p3对象实例化 如果已经有 p3 p3就重定义
4.匿名对象

​ 特点: 当前行执行完后 立即释放

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//构造函数分类
//按照参数分类: 无参构造(默认构造函数) 和 有参构造
//按照类型分类: 普通构造函数    拷贝构造函数
class Person
{
public:
	Person()
	{
		cout << "Person的默认构造函数调用" << endl;
	}

	Person(int age)
	{
		m_Age = age;
		cout << "Person的有参构造函数调用" << endl;
	}

	//拷贝构造函数
	Person(const Person& p)
	{
		cout << "Person的拷贝构造函数调用" << endl;
		m_Age = p.m_Age;
	}

	//析构函数
	~Person()
	{
		cout << "Person的析构函数调用" << endl;
	}
	int m_Age;
};

//构造函数的调用
void test01()
{
	//Person p;

	//1、括号法
	//Person p1(10);
	//Person p2(p);

	//注意事项一 
	//不要用括号法 调用无参构造函数  Person p3();  编译器认为代码是函数的声明

	//2、显示法
	//Person p3 = Person(10); //有参构造
	//Person p4 = Person(p3); //拷贝构造

	//Person(10); //匿名对象  特点: 当前行执行完后 立即释放

	//cout << "aaa" << endl;

	//注意事项二
	//不要用拷贝构造函数 初始化 匿名对象 
	//Person(p3); 编译器认为 Person p3对象实例化  如果已经有p3  p3就重定义

	//3、隐式法  
	Person p5 = 10; //Person p5 = Person(10);
	Person p6 = p5;
}

int main() {
	test01();
	//Person p(18);
	//Person p2(p);
	//cout << "p2的年龄: " << p2.m_Age << endl;
	system("pause");
	return EXIT_SUCCESS;
}

4.拷贝构造函数的调用时机

拷贝构造函数的调用时机
1、用已经创建好的对象来初始化新的对象
2、值传递的方式 给函数参数传值
3、以值方式 返回局部对象

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person
{
public:
	Person()
	{
		cout << "Person的默认构造函数调用" << endl;
	}

	Person(int age)
	{
		m_Age = age;
		cout << "Person的有参构造函数调用" << endl;
	}

	//拷贝构造函数
	Person(const Person &p)
	{
		cout << "Person的拷贝构造函数调用" << endl;
		m_Age = p.m_Age;
	}

	//析构函数
	~Person()
	{
		cout << "Person的析构函数调用" << endl;
	}

	int m_Age;

};

//1、用已经创建好的对象来初始化新的对象
void test01()
{
	Person p1(18);

	Person p2 = Person(p1);

	cout << "p2的年龄:" << p2.m_Age<< endl;

}

//2、值传递的方式 给函数参数传值
void doWork(Person p)
{

}
void test02()
{
	Person p1(100);

	doWork(p1);

}

//3、以值方式 返回局部对象
Person doWork2()
{
	Person p;
	return p;
}

void test03()
{
	Person p = doWork2();
}

/*	
	编译器优化代码后 release版本代码类似以下:
	void doWork2( Person &p ){};

	Person p;
	doWork2(p);
*/

int main(){
	//test01();
	//test02();
	test03();
	system("pause");
	return EXIT_SUCCESS;
}

5.构造函数的调用规则

构造函数的调用规则
1、编译器会给一个类 至少添加3个函数 默认构造(空实现) 析构函数(空实现) 拷贝构造(值拷贝)
2、如果我们自己提供了 有参构造函数,编译器就不会提供默认构造函数,但是依然会提供拷贝构造函数
3、如果我们自己提供了 拷贝构造函数,编译器就不会提供其他构造函数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//1、编译器会给一个类 至少添加3个函数    默认构造(空实现)   析构函数(空实现)   拷贝构造(值拷贝)
//2、如果我们自己提供了 有参构造函数,编译器就不会提供默认构造函数,但是依然会提供拷贝构造函数
//3、如果我们自己提供了 拷贝构造函数,编译器就不会提供其他构造函数
class Person
{
public:

	Person()
	{
		cout << "默认构造函数调用" << endl;
	}

	Person(int age)
	{
		m_Age = age;
		cout << "有参构造函数调用" << endl;
	}

	Person(const Person &p)
	{
		m_Age = p.m_Age;
		cout << "拷贝构造函数调用" << endl;
	}

	~Person()
	{
		cout << "析构函数调用" << endl;
	}
	int m_Age;
};

void test01()
{
	Person p1;//提供拷贝构造后,要自己提供默认构造,否则出错
	p1.m_Age = 20;

	Person p2(p1);

	cout << "p2的年龄为: " << p2.m_Age << endl;

}

int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

6.深拷贝与浅拷贝的问题以及解决

1.如果有属性开辟到堆区,利用编译器提供拷贝构造函数会调用浅拷贝带来的析构重复释放堆区内存的问题
2.利用深拷贝解决浅拷贝问题
3.自己提供拷贝构造函数,实现深拷贝

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person
{
public:

	Person(char* name, int age)
	{
		m_Name = (char*)malloc(strlen(name) + 1);

		strcpy(m_Name, name);

		m_Age = age;
	}

	Person(const Person& p)
	{
		m_Name = (char*)malloc(strlen(p.m_Name) + 1);
		strcpy(m_Name, p.m_Name);
		m_Age = p.m_Age;
	}

	~Person()
	{
		if (m_Name != NULL)
		{
			cout << "Person析构调用" << endl;
			free(m_Name);
			m_Name = NULL;
		}
	}

	char* m_Name; //姓名
	int m_Age;     //年龄
};


void test01()
{
	char name[] = "zky";
	Person p(name,18);
	cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;

	Person p2(p);
	cout << "姓名: " << p2.m_Name << " 年龄: " << p2.m_Age << endl;
}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

7.初始化列表

1.可以利用初始化列表语法 对类中属性进行初始化
2.语法:构造函数名称后 : 属性(值), 属性(值)…
2.1 Person(int a, int b, int c) : m_A(a), m_B(b), m_C©

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person
{
public:

	//Person(int a, int b, int c)
	//{
	//	m_A = a;
	//	m_B = b;
	//	m_C = c;
	//}

	//Person() :m_A(10), m_B(20), m_C(30)
	//{
	//}

	//构造函数名称后  : 属性(值), 属性(值)...
	Person(int a, int b, int c) : m_A(a), m_B(b), m_C(c)
	{
	}

	int m_A;
	int m_B;
	int m_C;
};

void test01()
{
	Person p(10, 20, 30);

	cout << "m_A = " << p.m_A << endl;
	cout << "m_B = " << p.m_B << endl;
	cout << "m_C = " << p.m_C << endl;
}

int main() {
	test01();
	system("pause");
	return EXIT_SUCCESS;
}
8.类对象作为类中对象

当其他类对象 作为本类成员,先构造其他类对象,再构造自身,析构的顺序和构造相反

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>

class Phone
{
public:

	Phone(string pName)
	{
		cout << "phone 的有参构造调用" << endl;
		m_PhoneName = pName;
	}
	~Phone()
	{
		cout << "phone 的析构函数调用" << endl;
	}
	string m_PhoneName;
};

class Game
{
public:
	Game(string gName)
	{
		cout << "Game 的有参构造调用" << endl;
		m_GameName = gName;
	}
	~Game()
	{
		cout << "Game 的析构函数调用" << endl;
	}
	string m_GameName;
};

class Person
{
public:

	Person(string name, string pName, string gName) : m_Name(name), m_Phone(pName), m_Game(gName)
	{
		cout << "Person 的有参构造调用" << endl;
	}

	void PlayGame()
	{
		cout << m_Name << "拿着 << " << m_Phone.m_PhoneName << " >> 牌手机,玩着 :" << m_Game.m_GameName << endl;
	}

	~Person()
	{
		cout << "Person 的析构函数调用" << endl;
	}
	string m_Name; //姓名
	Phone m_Phone; //手机
	Game  m_Game;  //游戏
};

void test01()
{
	//当其他类对象 作为本类成员,先构造其他类对象,再构造自身,析构的顺序和构造相反
	Person p("张三", "苹果", "王者荣耀");
	p.PlayGame();

	Person p2("李四", "三星", "消消乐");
	p2.PlayGame();
}

int main() {
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

9.explicit关键字

explicit用途: 防止利用隐式类型转换方式来构造对象

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class MyString
{
public:
	MyString(char* str)
	{

	}
	//explicit用途: 防止利用隐式类型转换方式来构造对象
	explicit MyString(int len)
	{

	}
};

void test01()
{


	MyString str1(10);

	MyString str2 = MyString(100);

	//MyString str3 = 10; // "10"

}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

10.new和delete

new和delete
1、malloc 和 new 区别
1.1、malloc 和 free 属于 库函数 new 和delete属于 运算符
1.2、malloc不会调用构造函数 new会调用构造函数
1.3、malloc返回void* C++下要强转 new 返回创建的对象的指针
2、注意事项 不要用void去接受new出来的对象,利用void无法调用析构函数
3、利用new创建数组
3.1、Person * pPerson = new Person[10];
3.2、释放数组时候 需要加[]
3.3、delete [] pPerson;
4、堆区开辟数组,一定会调用默认构造函数
5、栈上开辟数组,可不可以没有默认构造,可以没有默认构造

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person
{
public:
	Person()
	{
		cout << "Person构造函数调用" << endl;
	}

	Person(int a)
	{
		cout << "Person有参构造调用" << endl;
	}

	~Person()
	{
		cout << "Person析构函数调用" << endl;
	}
};

//malloc 和 new 区别
//malloc 和 free 属于 库函数     new 和delete属于 运算符
//malloc不会调用构造函数   new会调用构造函数
//malloc返回void* C++下要强转     new 返回创建的对象的指针

void test01()
{
	Person* p = new Person;

	delete p;
}

//注意事项 不要用void*去接受new出来的对象,利用void*无法调用析构函数
void test02()
{
	void* p = new Person;

	delete p;
}

//利用new开辟数组
void test03()
{
	//int * pInt = new int[10];
	//double * pD = new double[10];

	//堆区开辟数组,一定会调用默认构造函数
	Person* pPerson = new Person[10];

	释放数组时候  需要加[]
	//delete [] pPerson;

	//栈上开辟数组,可不可以没有默认构造,可以没有默认构造
	//Person pArray[10] = { Person(10), Person(20), Person(20) };

}

int main() {
	//test01();
	//test02();
	test03();

	system("pause");
	return EXIT_SUCCESS;
}
11.静态成员

1、静态成员变量
1.1、所有对象都共享同一份数据
1.2、编译阶段就分配内存
1.3、类内声明、类外初始化
1.4、访问方式有两种:通过对象访问、通过类名访问
1.5、静态成员变量也是有访问权限
2、静态成员函数
2.1、所有对象都共享同一份函数
2.2、静态成员函数 只可以访问 静态成员变量,不可以访问非静态成员变量(因为不知道要修改的是哪一个对象)
2.3、静态成员函数 也是有访问权限的
2.4、静态成员函数 有两种访问方式:通过对象 、通过类名

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;


class Person
{
public:
	//1、静态成员变量
	//静态成员变量 :编译阶段就分配了内存
	//类内声明 、类外初始化
	//静态成员变量 所有对象都共享同一份数据
	static int m_A;


	//2、静态成员函数
	//所有对象都共享同一个func函数
	static void func()
	{
		//m_C = 100; //静态成员函数 不能访问非静态成员变量
		m_A = 100; //静态成员函数 能访问静态成员变量
		cout << "func调用" << endl;
	}

	int m_C;

private:
	static int m_B; //私有静态成员变量 

	static void func2()
	{

	}
};

int Person::m_A = 0;
int Person::m_B = 0;


void test01()
{
	//1、通过对象进行访问
	Person p1;
	cout << p1.m_A << endl;

	Person p2;
	p2.m_A = 100;

	cout << p1.m_A << endl;

	//2、通过类名进行访问
	cout << Person::m_A << endl;

	//静态成员变量 也是有访问权限的,私有权限类外访问不到
	//cout << Person::m_B << endl;

}

void test02()
{
	//通过对象
	Person p1;
	p1.func();
	//通过类名
	Person::func();
	//Person::func2();  静态成员函数也是有访问权限的
}

int main() {

	//test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}
12.单例模式

单例模式 – 主席类案例
1、通过一个类 只能实例化唯一的一个对象
2、私有化
2.1、默认构造
2.2、拷贝构造
2.3、唯一实例指针
3、对外提供 getInstance 接口,将指针返回

单例模式 – 打印机案例
1、和主席类案例一样设计单例模式
2、提供打印功能并且统计打印次数

13.C++对象模型初探

1、类中的成员变量 和 成员函数 是分开存储的
2、只有非静态成员变量 属于类对象上
3、空类的sizeof结果 1

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//#pragma pack(1)

class Person
{
public:

	int m_A; //只有非静态成员变量  属于类对象上

	void func()  //成员函数  并不属于类对象上
	{

	}

	static int m_B; //静态成员变量  不属于类对象上

	static void func2()//静态成员函数  不属于类对象上
	{

	}

	double m_C;

};
int Person::m_B = 0;

void test01()
{
	//空类的sizeof结果是1  原因  每个对象都应该在内存上有独一无二的地址,因此给空对象分配1个字节空间
	// Person pArr[10]  pArr[0]  pArr[1]
	Person p1;
	//  空对象 大小 1  
	cout << "sizeof = " << sizeof(p1) << endl;
}


int main() {
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

14.this指针

this指针
1、this指针 指向 被调用的成员函数 所属的对象
2、this指针可以解决名称冲突
3、this指针 隐式加在每个成员函数中
4、*this 就是本体
p1.personAddPerson(p2).personAddPerson(p2).personAddPerson(p2); //链式编程

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person
{
public:
	Person(int age)
	{
		//用途1 :解决名称冲突
		this->age = age;
	}

	//this指针 隐式加在每个成员函数中
	bool compareAge(Person& p)
	{
		if (this->age == p.age)
		{
			return true;
		}
		return false;
	}

	Person& personAddPerson(Person& p)
	{
		this->age += p.age;
		return *this; //*this 就是本体
	}

	int age;
};

void test01()
{
	//this指针 指向 被调用的成员函数 所属的对象
	Person p1(10);

	cout << "p1的年龄为: " << p1.age << endl;

	Person p2(10);

	bool ret = p1.compareAge(p2);
	if (ret)
	{
		cout << "p1与p2年龄相等" << endl;
	}

	p1.personAddPerson(p2).personAddPerson(p2).personAddPerson(p2); //链式编程
	cout << "p1的年龄为: " << p1.age << endl;

}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

15.空指针访问成员函数

1、如果成员函数中没有用到this指针,可以用空指针调用成员函数
2、如果成员函数中用到了this,那么这个this需要加判断,防止代码down掉

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person
{
public:

	void showClass()
	{
		cout << "class Name is Person" << endl;
	}

	void showAge()
	{
		/*	if (this == NULL)
			{
			return;
			}*/
			//m_Age = 0;
		cout << "age = " << this->m_Age << endl;
	}

	int m_Age;
};


void test01()
{
	Person* p = NULL;

	//p->showClass();

	p->showAge();

}

int main() {
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

16.常对象和常函数

1、常函数
1.1、成员函数 声明后面加const
1.2、void showPerson() const
1.3、const目的是为了修饰成员函数中的this指针,让指针指向的值不可以修改
1.4、有些属性比较特殊,依然在常函数或者常对象中可以修改,需要加入关键字 mutable
2、常对象
2.1、const Person p
2.2、常对象也不许修改成员属性
2.3、常对象只能调用常函数
3、对于成员函数 ,可不可以 用static 和 const同时修饰 ,不可以

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person
{
public:
	Person(int age)
	{
		this->m_Age = age;
	}

	//常函数 : 修饰成员函数中的 this指针,让指针指向的值不可以修改
	void showPerson() const
	{
		//m_Age = 100;

		m_A = 100;

		//this指针的本质: const Person * const this 
		//this = NULL; 指针的指向不可以修改,而指针指向的值 可以改
		cout << "person age = " << this->m_Age << endl;
	}

	void func()
	{
		m_Age = 100;
		cout << "func调用" << endl;
	}

	int m_Age;

	mutable int m_A; //常函数中或常对象 有些特殊属性依然想修改,加入关键字 mutable
};

void test01()
{
	//常对象
	const Person p1(10);
	//p1.m_Age = 10;
	p1.m_A = 10;

	p1.showPerson();

	//p1.func(); //常对象 只能调用常函数
}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

17.友元

1、全局函数作为友元函数
1.1、利用friend关键字让全局函数 goodGay作为本类好朋友,可以访问私有成员
1.2、friend void goodGay(Building * buliding);
2、类作为友元类
2.1、让goodGay类作为 Building的好朋友,可以访问私有成员
2.2、friend class GoodGay;
3、类中的成员函数作为友元函数
3.1、//让GoodGay类中的 visit成员函数作为友元
3.2、friend void GoodGay::visit();

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>

class Building
{
	//利用friend关键字让全局函数  goodGay作为本类好朋友,可以访问私有成员
	friend void goodGay(Building* buliding);

public:
	Building()
	{
		this->m_SittingRoom = "客厅";
		this->m_BedRoom = "卧室";
	}

public:
	string m_SittingRoom; //客厅
private:
	string m_BedRoom; //卧室
};

//好基友全局函数  可以访问Building的私有属性
void goodGay(Building* buliding)
{
	cout << "好基友正在访问:" << buliding->m_SittingRoom << endl;

	cout << "好基友正在访问:" << buliding->m_BedRoom << endl;
}

void test01()
{
	Building buliding;
	goodGay(&buliding);
}

int main() {
	test01();


	system("pause");
	return EXIT_SUCCESS;
}

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
class Building;
class GoodGay
{
public:

	GoodGay();

	void visit();

	Building* m_building;
};

class Building
{
	//让goodGay类作为 Building的好朋友,可以访问私有成员
	friend class GoodGay;

public:
	Building();

	string m_SittingRoom;

private:
	string m_BedRoom;
};

Building::Building()
{
	this->m_SittingRoom = "客厅";
	this->m_BedRoom = "卧室";
}

GoodGay::GoodGay()
{
	this->m_building = new Building;
}

void GoodGay::visit()
{
	cout << "好基友正在访问: " << this->m_building->m_SittingRoom << endl;
	cout << "好基友正在访问: " << this->m_building->m_BedRoom << endl;
}

void test01()
{
	GoodGay gg;
	gg.visit();
}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
class Building;
class GoodGay
{
public:

	GoodGay();

	void visit(); //可以访问building的私有

	void visit2(); // 不可以访问building的私有

	Building* m_building;
};

class Building
{
	//让GoodGay类中的 visit成员函数作为友元
	friend void GoodGay::visit();
public:
	Building();

	string m_SittingRoom;

private:
	string m_BedRoom;
};

Building::Building()
{
	this->m_SittingRoom = "客厅";
	this->m_BedRoom = "卧室";
}

GoodGay::GoodGay()
{
	this->m_building = new Building;
}

void GoodGay::visit()
{
	cout << "好基友正在访问: " << this->m_building->m_SittingRoom << endl;
	cout << "好基友正在访问: " << this->m_building->m_BedRoom << endl;
}

void GoodGay::visit2()
{
	cout << "好基友正在访问: " << this->m_building->m_SittingRoom << endl;
	//cout << "好基友正在访问: " << this->m_building->m_BedRoom << endl;
}


void test01()
{
	GoodGay gg;
	gg.visit();
	gg.visit2();
}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值