C++中A类内部用B类作为成员变量时的一个坑:invalid use of incomplete type ‘class xxx‘

我们知道,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,确实更为繁琐和细致,写的时候一定要小心,从一个个坑中慢慢积累经验~

你可能感兴趣的:(c++)