关于C++中使用不完全类的问题

关于C++中使用不完全类的问题,第1张

学习黑马C++中成员函数做友元时遇到的问题

关于C++中使用不完全类的问题

问题

想要让Goodfriend::visit()作为类Building的友元函数

#include
using namespace std;
class Goodfriend;
class Building
{
	friend void Goodfriend::visit(Building building);
public:
	Building() :m_SittingRoom("客厅"), m_BedRoom("卧室") {}//初始化
public:
	string m_SittingRoom; //客厅
private:
	string m_BedRoom; //卧室
};
class Goodfriend {
public:
	void visit(Building building)
	{
		cout << "好友正在访问: " << building.m_SittingRoom << endl;//访问公有成员
		cout << "好友正在访问: " << building.m_BedRoom << endl;//访问私有成员
	}
};

int main() {
	Building b;
	Goodfriend gf;
	gf.visit(b);
	return 0;
}

结果VS报错:使用了未定义类型Goodfriend

于是修改为类Goodfriend在前面定义,同时也加上类Building的提前声明。

#include
using namespace std;
class Goodfriend;
class Building;
class Goodfriend {
public:
	void visit(Building building)
	{
		cout << "好友正在访问: " << building.m_SittingRoom << endl;//访问公有成员
		cout << "好友正在访问: " << building.m_BedRoom << endl;//访问私有成员
	}
};
class Building
{
	friend void Goodfriend::visit(Building building);
public:
	Building() :m_SittingRoom("客厅"), m_BedRoom("卧室") {}//初始化
public:
	string m_SittingRoom; //客厅
private:
	string m_BedRoom; //卧室
};

int main() {
	Building b;
	Goodfriend gf;
	gf.visit(b);
	return 0;
}

出现报错:使用了未定义类型Building

解释

经过上网查询,原因如下:

程序开头写的

class Goodfriend;

是前向声明,在声明之后,定义之前,此类是一个不完全类型(incompete type),即已知前向声明过的类是一个类型,但不知道包含哪些成员。不完全类型只能以有限方式使用,不能定义该类型的对象,不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。

因此虽然写了Goodfriend类的前向声明,但对于编译器来说,只知道有这么一个类,并不知道这个类有一个visit()函数,因此报错。

同理,当Goodfriend类放在Building类前面时,Building类也是一个不完全类,于是出现同样的错误。

错误C2027:使用了未定义类型

当在同一个源文件中定义了两个类,而两个类又相互之间进行引用(如方法中定义形参为另一个类的指针,方法体中通过指针引用成员)时就会报错:C2027:使用了未定义类型。

该错误可以通过前向声明和单独编译方法解决

前向声明:
class 类名;//前向声明

可以声明一个类而不定义它,这个声明被称为前向声明(forward declaration)。在声明之后,定义之前,类是一个不完全类型(incompete type),即已知前向声明过的类是一个类型,但不知道包含哪些成员。

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

单独编译:

关于多文件:

可以通过编译的源文件就是一个编译单元,一个程序,可以由一个编译单元组成,也可以有多个编译单元组成。如:我们可以将所有东西都放在一个.cpp文件内,然后编译器就将这个.cpp编译成.obj,这就是一个编译单元。C++允许程序员将组件函数放在独立的文件中,可以单独编译这些文件,然后将它们链接成可执行的程序。一个函数不能放到两个编译单元里面,但两个以上就可以分别放在一个单元,也就是cpp里面。一个.cpp对应一个.obj,然后将所有的obj链接起来(通过一个叫链接器的程序),组成一个.exe,也就是程序了。

如果一个.cpp要用到另一个.cpp定义的函数只需在这个.cpp文件中写上他的函数声明(C++在同一个项目下的不同文件都位于全局作用域下,在其他文件中也可以引用)

两个类之间相互引用成员

例如:定义了类A类B,A中使用了B定义的类型,B中也使用了A定义的类型


情形1:

在两个类中相互使用了另一个类作为方法参数或其他只是定义该类型的指针及引用行为

**解决:**使用前向声明即可解决

不允许引用未定义类型:

使用前向声明解决:


情形2:

使用前向声明之后,在类定义之前,类是一个不完全类型(incompete type),即已知前向声明过的类是一个类型,但不知道包含哪些成员,所以在使用前向声明后,类定义前,只能定义指向该类型的指针及引用而不能使用该类成员。

**解决:**仅仅定义指向该类型的指针及引用而不能使用该类成员。

在类定义之前不能使用类成员

通过单独编译和前向声明方法实现两个类之间相互引用成员 方案1:

使用预处理指令include,将单独编译的文件引入到预处理命令include的地方

头文件:

#pragma once
#include 
#include "SeparateCompilationClass1.h" //编译完成后,预处理器将文件的内容添加到程序中,该头文件就拥有了B类的完整声明
using namespace std;
class B; //使用向前声明,在编译器表示此为一个类类型,使头文件声明通过编译
class A
{
public:
    void fun(B *b); //由于是声明,所以并不使用类成员,向前声明可以通过编译
};

源文件:

#include "SeparateCompilationClass2.h" //A类的头文件,在其中引用了B的头文件,拥有B的完成声明,所以在本文件中可以使用B类成员
void A::fun(B *b)
{ //通过作用域运算符为A类添加成员定义
    cout << "A中的方法" << endl;
    cout << "使用B中成员:" << endl;
    b->fun(); //通过单独编译可以使用B中成员
}
方案2:

将原本在类内实现的函数挪到类外、程序中靠后的位置实现。

方案3:

使用指针or引用

解决 方案1:采用类内声明,类外定义
#include
using namespace std;
class Goodfriend;
class Building;
class Goodfriend {
public:
	void visit(Building building);//不完全类可以作为形参的类型
};
class Building
{
public:
	Building() :m_SittingRoom("客厅"), m_BedRoom("卧室") {}//初始化
	friend void Goodfriend::visit(Building building);
public:
	string m_SittingRoom; //客厅
private:
	string m_BedRoom; //卧室
};
void Goodfriend::visit(Building building)//采取类外实现
{
	cout << "好友正在访问: " << building.m_SittingRoom << endl;//访问公有成员
	cout << "好友正在访问: " << building.m_BedRoom << endl;//访问私有成员
}
int main() {
	Building b;
	Goodfriend gf;
	gf.visit(b);
	return 0;
}
方案2:采用指向Building类型的指针
#include
using namespace std;
class Goodfriend;
class Building;
class Goodfriend {
public:
	void visit();
	Goodfriend();
private:
	Building* building; //使用指针
};
class Building
{
	friend void Goodfriend::visit();
public:
	Building() :m_SittingRoom("客厅"), m_BedRoom("卧室") {}//初始化
public:
	string m_SittingRoom; //客厅
private:
	string m_BedRoom; //卧室
};
Goodfriend::Goodfriend() {
	building = new Building;
}
void Goodfriend::visit() {
	cout << "好友正在访问: " << building->m_SittingRoom << endl;//访问公有成员
	cout << "好友正在访问: " << building->m_BedRoom << endl;//访问私有成员
}
int main() {
	Goodfriend gf;
	gf.visit();
	return 0;
}

参考:

C++ 成员函数做友元遇到的问题 (错误C2027:使用了未定义类型)_纯白棒球帽的博客-CSDN博客

C++ 成员函数做友元——错误问题:类型未定义_Iron&CHEN的博客-CSDN博客_成员函数做友元报错

【C++】错误C2027:使用了未定义类型错误原因 两个类之间怎么相互使用成员 前向声明概念_列队猫的博客-CSDN博客_使用了未定义类型

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/3002770.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-27
下一篇 2022-09-27

发表评论

登录后才能评论

评论列表(0条)

保存