Объявление объектов одного класса как членов другого (C ++) - PullRequest
0 голосов
/ 10 февраля 2019

По какой-то причине мой компилятор не позволяет мне использовать объекты другого класса в качестве членов другого класса.Вот мой код:

в Parameter.h:

class Parameter {
     private:
          string type;
          string name;
     public:
          Parameter() {};
          string toString();
          friend class Predicate;
};

Затем в Predicate.h:

#include "Parameter.h"
class Predicate {
     private:
          Parameter lParam;
          Parameter rParam;
          string type;
     public:
          Predicate() {};
          string toString();
          friend class Parameter;
};

Когда я пытаюсь скомпилировать, я получаю ошибкиговоря, что параметр в Predicate.h не называет тип, и что он не был объявлен в этой области.Я попытался поместить участников как в приватную, так и в публичную версию, а также объявить класс друзей как в приватной, так и в публичной.Я также пытался использовать указатели на объекты.Что я делаю неправильно?Спасибо.

1 Ответ

0 голосов
/ 11 февраля 2019

Хотя вы еще не предоставили MVCE , основываясь на описанной вами ошибке:

error: «Параметр» не называет тип

вы, похоже, испытываете "круговое включение" между Parameter.h и Predicate.h, как предлагается в комментариях.

Это происходит, когда вы объявляете два класса, которые обазнать о другом (Parameter и Predicate).Рассмотрим Predicate.Во время Predicate объявления компилятору уже нужно знать о существовании Parameter, так как он появляется как член в Predicate.

Первыйпопытка решения будет включать Parameter.h, что обеспечивает объявление Parameter.Но, Parameter требует, чтобы Predicate уже было объявлено, чтобы сделать его friend class.Это круговая зависимость .

Рекомендуемый метод решения этой проблемы - использовать так называемое предварительное объявление .

// Parameter.h
#pragma once                                         
#include <string>                                    

class Predicate;  // Forward declare Predicate

class Parameter {                                    
private:                                             
    std::string type;                                
    std::string name;                                
public:                                              
    Parameter() {};                                  
    std::string toString() { return "Parameter"; };  
    friend class Predicate;                          
};                                                   

Таким образом, это позволяет нам завершить объявление Parameter без необходимости включать весь файл Predicate.h.С другой стороны, Predicate.h может продолжать включать Parameter.h без проблем, поскольку циклическая зависимость была нарушена.

Обратите внимание, что если вы вызываете любой из Predicate методов из Parameter взаголовок, предварительные объявления не будут работать.Это потому, что для вызова любых методов необходимо полное объявление класса.Вы можете обойти это путем реализации методов Parameter в исходном файле.

См. Этот аналогичный вопрос для более общего обсуждения.

...