C++基础(15)——类和对象、友元

1.初始化列表

1.1作用

C++提供给了初始化列表语法,用来初始化属性

1.2语法

构造函数():属性1(值1),属性2(值2),属性3(值3)……{}

1.3示例

我们一般都是这样对函数初始化:

#include<iostream>
using namespace std;

class Person {
public:
	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() {

	return 0;
}

学到初始化列表后,我们可以进行如下操作:

#include<iostream>
using namespace std;

class Person {
public:
	Person() :m_A(10), m_B(20), m_C(30) {

	}
	int m_A;
	int m_B;
	int m_C;
};

void test01() {
	Person p;
	cout << "m_A=" << p.m_A << endl;
	cout << "m_B=" << p.m_B << endl;
	cout << "m_C=" << p.m_C << endl;
}

int main() {
	test01();
	return 0;
}

但是这种就把m_A,m_B,m_C写死了,如何才能动态的调整呢?我们可以进行如下的操作:

#include<iostream>
using namespace std;

class Person {
public:
	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(30,20,10);
	cout << "m_A=" << p.m_A << endl;
	cout << "m_B=" << p.m_B << endl;
	cout << "m_C=" << p.m_C << endl;
}

int main() {
	test01();
	return 0;
}

 2.类对象作为类成员

c++类中的成员可以是一个类的对象,我们称为该成员为对象成员

class A{};
class B{
    A a;
}

B类中由对象A作为成员,A为对象成员。

注意:当其他类对象作为本类成员,构造时候先构造类对象,再构造自身

#include<iostream>
using namespace std;

class Phone {
public:
	Phone(string pName) {//创建类的时候就告诉你手机的品牌
		p_name = pName;
		cout << "Phone的构造函数调用" << endl;
	}
	string p_name;
};
class Person {
public:
	Person(string name, string pName) :m_name(name),m_phone(pName)//初始化列表赋值,在类创建的时候就告诉你人名和手机名
	{
		cout << "Person的构造函数调用" << endl;
	}
	string m_name;
	Phone m_phone;
};

void test01() {
	Person p("张三", "苹果");
	cout << p.m_name << "拿着" << p.m_phone .p_name<< endl;

}

void main() {
	
	test01();
}

可以看到先构造的是Phone类,后构造的是Person类。但是析构函数释放的顺序是和构造函数的顺序相反的。 

3.静态成员函数

#include<iostream>
using namespace std;

class Person {
public:
	//静态成员函数
	static void func()
	{
		m_A = 100;//静态成员函数可以访问静态成员变量
		//m_B = 200;静态成员函数不能访问非静态成员变量
		cout << "static void func 调用" << endl;
	}
	static int m_A;//静态成员变量
	int m_B;//非静态成员变量

private://静态成员也是有权限限制的
	static void func2() {
		cout << "static void func2()调用" << endl;
	}
};

void test01() {
	//访问静态成员函数有两种方式
	//1.通过对象调用
	Person p;
	p.func();

	//2.通过类名调用
	Person::func();
	//Person::func2();类外不能访问私有的静态成员
}

void main() {
	test01();
}

 4.C++对象模型和this指针

4.1成员变量和成员函数分开存储

在c++中,成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上。

#include<iostream>
using namespace std;

class Person {
public:
	
};

void test01() {
	Person p;
	cout << "size of p=" <<sizeof(p)<< endl;
}

void main() {
	
	test01();
}

可以看到空对象也是占用一个空间,C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置,每个空对象也应该有一个独一无二的内存地址。

#include<iostream>
using namespace std;

class Person {
public:
	int m_A;//非静态成员变量,属于类的对象上
	static int m_B;//静态成员变量,不属于类的对象上,不占字节
	void func(){}//非静态成员函数,也不属于类的对象上
	static void func2(){}//静态成员函数不属于类的对象上
};

void test01() {
	Person p;
	cout << "size of p=" <<sizeof(p)<< endl;
}
void test02() {
	Person p;
	cout << "size of p=" << sizeof(p) << endl;
}

void main() {
	
	test02();
}

所以,只有非静态成员变量属于类的对象上,剩下的都不属于,一个空对象的sizeof是1。

4.2this指针的用途

由于每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码,那么问题是:这一块代码是如何区分哪个对象调用的自己呢?

C++通过提供特殊的对象指针,this指针解决上述问题,this指针指向被调用的成员函数所属的对象:

  • this指针是隐含每一个非静态成员函数内的一种指针
  • this指针不需要定义,直接使用即可

this指针的用途:

  • 当形参和成员变量同名时,可以用this指针
  • 在类的非静态成员函数中返回对象本身,可以使用return *this

4.2.1this解决名称冲突的案例

输出不是一个年龄。我们可以把成员变量age写为m_age;可以改为如下:

两种方式。

4.2.2返回对象本身用*this

#include<iostream>
using namespace std;

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

	Person& PersonAddAge(Person& p) {
		this->age += p.age;//把别人年龄加到自身
		return *this;//this指向的p2的指针,而*this指向的是p2的这个对象本体
	}

	int age;
};

void test01() {
	Person p1(18);
	cout << "p1的年龄是:" << p1.age<<endl;
}
void test02() {
	Person p1(10);
	Person p2(10);
	p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);

	cout << "p2的年龄是:" << p2.age << endl;
}


void main() {
	
	test02();
}

 4.2.3.空指针访问成员函数

C++空指针也是可以调用成员函数的,但是也要注意有没有用到this指针,如果用到this指针,需要加以判断保证代码的健壮性。

#include<iostream>
using namespace std;

class Person {
public:
	void showClassName() {
		cout << "this is Person class" << endl;
	}

	void showPersonAge() {
		if (this == NULL) {
			return;
		}
		cout << "age=" << this->m_age << endl;
	}

	int m_age;
};

void test01() {
	Person* p=NULL;
	p->showClassName();
	p->showPersonAge();
}


void main() {
	
	test01();
}

 4.3const修饰成员函数

4.3.1常函数

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加上关键字mutable后,在常函数中依然可以修改

注:

this指针的本质是指针常量,指针的指向是不可以修改的

Person *const this ;const修饰this指针的指向,因此this指针不可以修改指针的指向。如果要让this指针指向的值也不可以修改就需要:const Person *const this;在成员函数中的定义如下:


class Person {
public:
	void showPerson()const {
		//this->m_A=100;指针的值也不可以修改
		//this = NULL;指针的指向不可以修改
	}

	int m_A;
};

在成员函数后面加一个const,修饰的时this指向,让指针指向的值也不可以修改

常函数:其实就是在成员函数的屁股后面加一个const,这个const是用来修饰this指针的,来让成员函数的指针指向和值都不可以修改,如果需要修改的话可以在变量的前面加一个mutable,如下所示:

                            

这时候就不会报错,m_B就可以修改。

4.3.2常对象

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数

 在对象前加一个const就是常对象。

 常对象也只能调用常函数:

 5.友元

例如家里有客厅(public)、卧室(private),客厅所有的客人都可以访问,但是我们的卧室是私有的,也就是只有你可以进去,你也可以允许你的闺蜜进去。

在程序里有些私有属性,也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术。

友元的目的就是让一个函数或者类访问另一个类中私有成员。友元的关键词是friend

友元的三种实现:

  • 全局函数做友元
#include<iostream>
using namespace std;


class Building {
public:
	Building() {
		m_SittingROOM = "客厅";
		m_BedRoom = "卧室";

	}

public:
	string m_SittingROOM;//客厅

private:
	string m_BedRoom;//卧室
};

//全局函数
void goodGay(Building *building) {
	cout << "好朋友的全局函数正在访问:" << building->m_SittingROOM << endl;

}

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


void main() {
	
	test01();
}

                  

                   

 可以看到全局函数不能访问私有变量。如果要访问可以加一个friend作为友元

  

可以看到不再报错。

  • 类做友元
#include<iostream>
using namespace std;


class Building {
	//Goodgay类是本类的好朋友,可以访问本类中私有成员
	friend class GoodGay;

public:
	Building();//一般我们都是类内实现成员函数,现在我们尝试一下类外

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

class GoodGay {
public:
	GoodGay();
	void visit();//参观函数访问Building中的属性

	Building* buildding;
};

Building::Building() {//类外写成员函数
	m_SittingRoom = "客厅";
	m_BedRoom = "卧室";
}

GoodGay::GoodGay() {
	//创建一个建筑物的对象
	buildding = new Building;
}

void GoodGay::visit() {
	cout << "好朋友类正在访问:" << buildding->m_SittingRoom << endl;
	cout << "好朋友类正在访问:" << buildding->m_BedRoom << endl;
}

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


void main() {
	
	test01();
}

  • 成员函数做友元
#include<iostream>
using namespace std;


class Building {
	//告诉编辑器,Goodgay类下的visit()是本类的好朋友,可以访问本类中私有成员
	friend void GoodGay::visit();

public:
	Building();//一般我们都是类内实现成员函数,现在我们尝试一下类外

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

class GoodGay {
public:
	GoodGay();
	void visit();//让visit函数可以访问Building中私有成员
	void visit2();//让visit2不可以访问Building中私有成员

	Building* buildding;
};

Building::Building() {//类外写成员函数
	m_SittingRoom = "客厅";
	m_BedRoom = "卧室";
}

GoodGay::GoodGay() {
	//创建一个建筑物的对象
	buildding = new Building;
}

void GoodGay::visit() {
	cout << "好朋友类正在访问:" << buildding->m_SittingRoom << endl;
	cout << "好朋友类正在访问:" << buildding->m_BedRoom << endl;
}
void GoodGay::visit2() {
	cout << "好朋友类正在访问:" << buildding->m_SittingRoom << endl;
	//cout << "好朋友类正在访问:" << buildding->m_BedRoom << endl;
}

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


void main() {
	
	test01();
}

visit()可以访问私有属性,visit2不可以访问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI炮灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值