Указатели на членов класса в класс с закрытым конструктором

Допустим, у меня есть класс с частным конструктором, и этот класс будет использоваться для представления одного объекта. Допустим, у меня есть некоторые нестатические элементы, к которым я хочу получить доступ без использования оператора разрешения области. Я заметил, что могу добиться этого, создав для этого указатель на тип класса. Мне было интересно, почему я могу объявлять указатели на этот класс, даже если конструктор по умолчанию является закрытым? Вот пример программы.


// Example program
#include <iostream>
#include <string>


class OnlyOne{
    public:
    void Location(){
        std::cout<<10<<std::endl;
        
    }
    private:
    OnlyOne();
};
int main()
{
    //does not work Location() is not a static member
    //OnlyOne::Location();
     
      // doesn't work because default constructor is private.
     //OnlyOne one;
    //one.Location();
    
    
    OnlyOne* two=nullptr;
    two->Location();
}

Я искал в Интернете, чтобы увидеть, смогу ли я найти ответ, и не смог получить то, что ищу.


person Nice    schedule 19.07.2020    source источник
comment
вы можете объявить указатели типов, которые даже не имеют конструктора, например, объединение. объявление указателя — это одно, а создание экземпляра — другое.   -  person AndersK    schedule 19.07.2020
comment
Примечание. Вы можете обнаружить, что OnlyOne* two=nullptr; two->Location(); работает как положено. Одним из практически бесконечных возможных проявлений неопределенного поведения является ожидаемое поведение. Поистине неприятная штука, UB, потому что легко доказать, что она у тебя есть, и очень трудно доказать, что у тебя ее нет. В этом случае Location не использует OnlyOne, для которого она была вызвана, никогда не использует this, поэтому программа может никогда не заметить, что у нее плохой this.   -  person user4581301    schedule 19.07.2020
comment
Если я правильно понимаю, решение, данное Али Аскари, решает эту проблему с помощью шаблона Singleton.   -  person Nice    schedule 19.07.2020


Ответы (2)


Когда вы объявляете указатель некоторого типа, этот тип не обязательно должен быть конструируемым. На самом деле, этот тип даже не обязательно должен быть полным. Итак, эта строка:

OnlyOne* two = nullptr;

это прекрасно.

Обратите внимание, что эта строка:

two->Location();

вызывает неопределенное поведение, так как нет объекта, на который указывает two, и поэтому нет объекта, для которого можно вызвать функцию-член Location.

На самом деле, поскольку этот тип не является конструируемым, two никогда не может указывать на допустимый объект. Вы должны предоставить способ создания такого объекта либо путем предоставления общедоступного конструктора, либо с помощью статической функции-члена, которая создает и возвращает такой объект.

person cigien    schedule 19.07.2020
comment
Будет ли two-›Location() по-прежнему иметь неопределенное поведение, если я изменю void location() на OnlyOne* Location() и оператор return на return (OnlyOne *)10? - person Nice; 19.07.2020
comment
Это позволит вам вернуть OnlyOne*, но вы не можете вызвать Location без действительного экземпляра OnlyOne. Также обратите внимание, что return (OnlyOne*)10 лжет компилятору. Если вы солжете компилятору, чтобы устранить ошибку компилятора, все, что вы сделали, это переместили ошибку из времени компиляции во время выполнения, где ее было бы труднее найти. Вам нужен действительный OnlyOne, а адрес 10 почти наверняка не содержит OnlyOne. - person user4581301; 19.07.2020

Вы можете использовать singleton pttern для реализации классов с закрытым конструктором:


// Example program
#include <iostream>
#include <string>


class OnlyOne{
    public:

    static OnlyOne* instance() {
        static OnlyOne obj;
        return &obj;
    }

    void Location(){
        std::cout<<10<<std::endl;
        
    }
    private:
    OnlyOne() { }
};
int main()
{
    //does not work Location() is not a static member
    //OnlyOne::Location();
     
      // doesn't work because default constructor is private.
     //OnlyOne one;
    //one.Location();
    
    
    OnlyOne* two=OnlyOne::instance();
    two->Location();
}
person Ali Askari    schedule 19.07.2020