Различное поведение c++ со значением по умолчанию для публичной и частной области видимости

У меня два вопроса

1) Почему мы можем указать значение по умолчанию, если член является общедоступным, а когда он является частным, нам не разрешено? Возьмите пример ниже:

#include <iostream>
using namespace std;
class Test
{
private:
    int a=5;
public:
    Test()
    {
        cout<<a<<endl;
        cout<<"default const";
        a=0;
    }

};
int main()
{
    Test x;
    cout<<x.a;

}

Для этого мы получаем ошибку ниже:

Compile Errors :
prog.cpp: In function 'int main()':
prog.cpp:6:11: error: 'int Test::a' is private
     int a=5;
           ^
prog.cpp:19:13: error: within this context

Если я сделаю это общедоступным, как показано ниже:

#include <iostream>
using namespace std;
class Test
{ 
public:
    int a=5;
    Test()
    {
        cout<<a<<endl;
        cout<<"default const";
        a=0;
     }

};
int main()
{
    Test x;
    cout<<x.a;

}

Мы получаем результат как:

5
default const0

2) Мой следующий вопрос: почему у нас такое поведение? Также, когда мы предоставляем это значение по умолчанию, почему значение конструктора переопределяет значение по умолчанию, предоставленное в классе?

Ошибка, которую вы видите, отсутствует в конструкторе класса и не имеет ничего общего со значениями по умолчанию. Ошибка возникает в выражении cout << x.a. И это демонстрирует всю цель контроля доступа public / private.

Kerrek SB 10.09.2018 10:53

Поскольку вы пытаетесь получить к нему доступ из main, компилятор просто сообщает вам, какое объявление переменной является проблемой (это просто включает инициализацию).

George 10.09.2018 10:53

Мета-комментарий: этот вопрос не о «различном поведении»: поскольку один из двух примеров плохо сформирован, он недействителен C++ и вообще не «ведет себя». «Различное поведение» обычно означает, что две вещи компилируются и запускаются, но при одних и тех же входных данных производят разные наблюдаемые эффекты.

Kerrek SB 10.09.2018 10:55

Я не думаю, что это настоящее полное сообщение об ошибке от вашего компилятора.

molbdnilo 10.09.2018 11:20
6
5
115
4

Ответы 4

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

  2. Достаточно просто, сначала присваиваются все значения по умолчанию (конструируются, см. Комментарий), затем выполняется код внутри конструктора. Вот почему вы видите 5 внутри конструктора.

Если вы хотите, чтобы конструктор изменил значение инициализации a, вы можете использовать список инициализаторов:

Test(): a{0}
{
    cout<<a<<endl;
    cout<<"default const";
}

И это напечатает 0, значение a никогда не будет 5 при использовании этого конструктора.

«значения по умолчанию присваиваются» - нет, значения по умолчанию не присваиваются (значения по умолчанию строятся). Вы можете увидеть это здесь coliru.stacked-crooked.com/a/26f3951020f96db3 Это небольшая формальность, но я думаю, что о ней стоит упомянуть.

Andrew Kashpur 10.09.2018 11:13

Да, ты прав. Я отредактировал свой ответ. Я просто хотел, чтобы ответ был простым, но я полагаю, что он должен быть максимально точным: P

N00byEdge 10.09.2018 16:48

Мы также можем присвоить значение частным переменным-членам, но кажется, что вы обращаетесь к частной переменной-члену a вне класса, что недопустимо.

К (2) и, в частности, «почему»: инициализаторы в классе действуют как дефолт, которые не зависят от каких-либо входных данных, переданных конструкторам, тогда как инициализаторы конструкторов можно рассматривать как специализацию. Представьте себе класс с 10 конструкторами, всем требуется одно и то же статическое значение для x, вы должны придерживаться инициализаторов внутри класса, чтобы избежать избыточного кода.

Сообщение об ошибке немного вводит в заблуждение; проблема в вашем использование. Объявление было показано вам для контекста, и поскольку объявление включает инициализатор, это похоже, ошибка связана с этой инициализацией. Но это не так.

Итак, у нас нет такого поведения.

Что касается того, почему присвоение значения члену "переопределяет" ваше инициализированное значение, ну, это то, что делает присвоение. Когда вы инициализируете что-то, оно получает значение, а затем, когда вы назначаете ему позже, теперь вместо этого оно имеет значение что. Это то же самое, что и простая локальная переменная:

int x = 42;
x = 3;

Какую ценность сейчас имеет x?

Код в теле конструктора - «позже». К моменту его запуска все инициализации участников (будь то по умолчанию или с указанными вами значениями) уже завершены.

Другие вопросы по теме