【C++】友元,向前声明,黑马程序员案例,解决错误:错误C2653:不是类或命名空间,错误C2027:使用了未定义类型

author:&Carlton

tag:C++

topic:【C++】友元,向前声明,黑马程序员案例,解决错误:错误C2653:不是类或命名空间,错误C2027:使用了未定义类型

website:黑马程序员C++

date:2023年7月20日


目录

友元

向前声明

不完全类型

源代码及相关解释

参考


友元

        

        在A类中声明B类为友元,则B可以访问A类中的私有属性

        这里涉及了类与类之间的相互访问从编译器的视角来看,很容易带来“我认不清人”的问题,因为编译器的编译顺序是固定的,没有那么智能,所以我们要告诉它,使用向前声明

        因为编译器的"迟钝",编译常见的报错有:

        ①不是类或命名空间

        ②使用了未定义类型

        但原因是类似的,可归为上述抽象的“认不得”,解决方法可以使用向前声明,让它认得。

向前声明

        类A要通过成员函数访问类B,则先声明类B(让编译器在看到类A的声明时初步认知类B),然后声明类A(让编译器知道类A大概有些啥东西,这里头有对类B的引用,此时编译器已经初步认知过不完全类型B),再定义类B(编译器完全了解类B了,知道了类B的属性,发现了类A是类B的友元,此时编译器已经初步认识不完全类型A了),最后定义类A(编译器完全了解类A了,主要去知道了类A如何通过成员函数访问类B的某个属性了

        为何忽然变得这么麻烦呢?(和以往我们不做友元的时候相比)

        因为我们要在类B的定义里对类A进行友元声明。

不完全类型

        不完全类型只能以有限方式使用,不能定义该类型的对象,不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。

源代码及相关解释

关键点1:
        向前声明类Building,使得类ReneeHappy的向前声明中“Building* m_building”有效,此时Building还是一个不完全类型,不能使用它的成员属性或者成员函数。

        在使用向前声明后,类定义前,只能定义指向该不完全类型building的指针及引用而不能使用该类成员(正如在类ReneeHappy中的"Builiding* m_building")。

        但与Building类属性有关的ReneeHappy成员函数visit的定义就需要放在类Building定义的后头了,因为需要让编译器先知道类Building到底有什么成员才能使用其成员

关键点2:

        为何类Renee不需要像类ReneeHappy那样进行向前声明就可以访问类Building的成员呢?
        是因为在类Building的定义中对类Renee是整体声明,不需要了解它有什么成员,而对类ReneeHappy是需要知道它有成员函数visit的。

请看!源代码:

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

class Building;

/*
关键点1:
向前声明类Building,使得类ReneeHappy的向前声明中“Building* m_building”有效
此时Building还是一个不完全类型,不能使用它的成员属性或者成员函数。
在使用向前声明后,类定义前,只能定义指向该不完全类型building的指针及引用而不能使用该类成员(正如在类ReneeHappy中的"Builiding* m_building")
但与Building类属性有关的ReneeHappy成员函数visit的定义就需要放在类Building定义的后头了,因为需要让编译器先知道类Building到底有什么成员才能使用其成员
*/

//tips:不完全类型只能以有限方式使用,不能定义该类型的对象,不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数

//类ReneeHappy的声明
class ReneeHappy
{
public:
	Building* m_building;
	//构建ReneeHappy时让指向Building类的指针类型building指向堆中的内存区
	ReneeHappy();
	void visit();
};

/*
向前声明类ReneeHappy,使得编译器在后头类Building的定义中认识ReneeHappy是一个不完全类型,可以对其进行友元声明操作
*/

class Building
{
	//声明全局函数是Building类的友元
	friend void ReneeVisit();
	//声明类Renee是Building的友元
	friend class Renee;
	//声明类ReneeHappy的成员函数visit是Building的友元
	friend void ReneeHappy::visit();
public:
	Building();//声明一下构建函数
	string m_SittingRoom;
private:
	string m_BedRoom;
};

//在类外定义Building的构建函数并使用初始化列表
Building::Building(): m_SittingRoom("Carlton's 客厅"),m_BedRoom("Carlton's 卧室")
{
	cout << "Building的构建函数" << endl;
}

//全局函数ReneeVisit的定义
void ReneeVisit()
{
	Building building;
	cout << "全局函数ReneeVisit正在访问:" << building.m_SittingRoom << endl;
	cout << "全局函数ReneeVisit正在访问:" << building.m_BedRoom << endl;
}

//类Renee的定义
class Renee
{
public:
	Building* m_building;
	//构建Renee时让指向Building类的指针类型building指向堆中的内存区
	Renee();
	void visit()
	{
		cout << "类Renee正在访问: " << m_building->m_SittingRoom << endl;
		cout << "类Renee正在访问: " << m_building->m_BedRoom << endl;
	}
};

//类Renee的构建函数写在外头
Renee::Renee()
{
	m_building = new Building;
}

/*
关键点2:
为何类Renee不需要像类ReneeHappy那样进行向前声明就可以访问类Building的成员呢?
是因为在类Building的定义中对类Renee是整体声明,不需要了解它有什么成员,而对类ReneeHappy是需要知道它有成员函数visit的
*/

//类ReneeHappy的构建函数和成员函数visit写在类外头
ReneeHappy::ReneeHappy()
{
	m_building = new Building;
}

void ReneeHappy::visit()
{
	cout << "类ReneeHappy的成员函数visit正在访问: " << m_building->m_SittingRoom << endl;
	cout << "类ReneeHappy的成员函数visit正在访问: " << m_building->m_BedRoom << endl;
}

//全局函数做友元
void test01()
{
	ReneeVisit();
}

//类做友元
void test02()
{
	class Renee p;
	p.visit();
}

//成员函数做友元
void test03()
{
	class ReneeHappy p;
	p.visit();
}

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

参考

        第一个链接的博主更书面地介绍了向前声明、另外分享了单独编译的解决办法

        第二个和第三个链接的博主对解决问题的过程做了更具体、详细的记录。 

        谢谢你们!真的很用心🤠      

http://t.csdn.cn/OtjMW 列队猫🐱

http://t.csdn.cn/EafaC  纯白棒球帽

http://t.csdn.cn/y98FV 南哥

 

欢迎指正与分享,谢谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值