我们知道,C++中是可以在定义类时嵌套另一个类作为本类的成员的,但是在使用时,有一些细节需要格外注意。
invalid use of incomplete type ‘class xxx’ 问题的出现
首先我们用一段代码来引出这个坑。
我们定义两个类,一个 Person
,一个Student
。在 Student
中,有一个 Person
类型的成员变量。
不过,我们先定义 Student
类,再定义 Person
类。并在 Student
类的定义之前先声明好 Person
类。
class Person; // 前向声明Person类
class Student {
private:
Person person; // 定义一个Person类的对象作为成员变量
int grade;
public:
Student(string name, int age, int grade) : person(name, age), grade(grade) {}
void print_info() {
cout << "Name: " << person.get_name() << endl; // 调用Person类的成员函数
cout << "Age: " << person.get_age() << endl;
cout << "Grade: " << grade << endl;
}
};
class Person {
private:
string name;
int age;
public:
Person(string name, int age) : name(name), age(age) {}
string get_name() { return name; }
int get_age() { return age; }
};
对于上面这段的代码,将会在调用 Student
对象的 print_info()
函数时报错:invalid use of incomplete type ‘class xxx’。
问题分析与解决策略
问题分析
- C++中,如果类中定义另一个类(包括引用和指针,比如
Person
,Person &
,Person *
)作为成员变量,那么一定要保证另一个类在本类之前已定义。如果另一个类没定义,而是采用的先写一句声明语句的方式(即前向声明),则在本类成员函数中访问另一个类的成会报错。 - 因为另一个类只是声明了但未定义,C++编译器又是从上到下编译的,所以编译到这个方法时还不知道另一个类的结构。
解决策略
为了解决上述问题,实际上有两种策略:
- 可以让另一个类提前定义好,这是最简单和直接的方法,就是将另一个类的定义放在本类之前,这样编译器就可以知道另一个类的大小和结构。
- 如果上述方案不能解决,那么可以在本类中只声明成员函数,不定义成员函数的函数体。而在类外部,当另一个类已定义完毕后,再去写成员函数的函数体。也就像下面这样:
class Person; // 前向声明Person类 class Student { private: Person person; // 定义一个Person类的对象作为成员变量 int grade; public: Student(string name, int age, int grade) : person(name, age), grade(grade) {} void print_info(); // 只声明不定义 }; class Person { private: string name; int age; public: Person(string name, int age) : name(name), age(age) {} string get_name() { return name; } int get_age() { return age; } }; // 在Person类已定义完毕后再定义Student::print_info()函数 // 编译到这时编译器已经知道Person类的信息了,所以不会报错 void Student::print_info() { cout << "Name: " << person.get_name() << endl; // 调用Person类的成员函数 cout << "Age: " << person.get_age() << endl; cout << "Grade: " << grade << endl; }
最后,不得不说,C++的语法相较Java,确实更为繁琐和细致,写的时候一定要小心,从一个个坑中慢慢积累经验~