Почему я не могу создать экземпляр класса, конструктор которого является закрытым в другом классе?

У меня есть два класса; Salary, предназначенная для хранения информации и расчетов, касающихся заработной платы сотрудника и Employee который имеет объект типа class Salary и некоторые элементы, такие как имя и адрес сотрудника...

  • Я хочу предотвратить создание экземпляров class Salary, кроме class Employee. Поэтому я объявил конструкторов Salary частными и сделал Employee другом Salary. Но я получаю ошибки:

    class Employee;
    
    class Salary {
        public:
    
        private:
            Salary() : revenue_{}, cost_{} {}
            Salary(int x, int y) : revenue_{ x },
            cost_{ y } {
    
            }
            int revenue_, cost_;
            friend class Employee;
    };
    
    class Employee {
        public:
            std::string name_;
            Salary sal;
    };
    
    int main(){
    
        Employee emp{}; // "Salary::Salary()" is inaccessible
    }
    
  • Проблема исчезнет, если я перейду объявить main:

    int main(int, char*[]);
    

    И сделать main другом class Salary как в Зарплате:

    class Salary {
        //...
        friend int main(int argc, char* argv[]);
    };
    

Теперь программа компилируется правильно!

*** Другое дело, если я объявлю объект таким образом:

Employee emp; // ok
Employee emp{}; // error?

Ответы

Ответ 1

Поскольку вы не предоставляете конструктор для скобок Employee при инициализации Employee emp{}; выполнит агрегатную инициализацию, что по сути означает, что каждый элемент инициализируется один за другим с использованием правил по умолчанию в контексте main(). Поскольку main() не имеет доступа к конструктору Salary, происходит сбой.

Как уже отмечали другие, добавление конструктора Employee умолчанию решит вашу проблему:

class Employee {
    public:
        Employee() = default;
        std::string name_;
        Salary sal;
};

Ответ 2

Вам нужен Employee Ctor, чтобы вызвать Ctor Salary. Ctor of Salary не доступен с main.

например:

class Employee {
public:
    Employee() : sal() {}
    public:
        std::string name_;
        Salary sal;
};

Ответ 3

Вы должны явно объявить конструктор по умолчанию класса Employee таким образом, вы можете инициализировать объект с помощью uniform initialization:

class Employee {
    public:
        Employee(){} // add it
        std::string name_;
        Salary sal;
};

int main(){
    Employee emp{}; // now this should compile

}

Ответ 4

Если вы удалите "{}" после "Employee emp" в своей функции main(), она будет прекрасно скомпилирована (gcc 7.3.1 в Fedora 27).