2016-08-24 3 views
0

Почему компилятор (clang) жалуется на то, что mymy неинициализирован, когда я конкретно сказал, что это постоянное значение, удерживая 50. И почему это позволяет мне изменить его на 23 ... когда я все еще говорил ему быть постоянным?В инициализации класса константного члена

#include <iostream> 

class Base 
{ 
public: 

    Base(int y) : my(y) {std::cout << "Base:" << my << std::endl;} 
private: 
    int my; 
}; 

class Derived : public Base 
{ 
public: 
    Derived() : Base(mymy), mymy(23) {std::cout << "Derived:" << mymy << std::endl;} 


private: 

    const int mymy = 50; 
}; 

int main() 
{ 
    Derived a; 
} 

Странно, coliru компилируется без hick. http://coliru.stacked-crooked.com/a/63629c2d99bf6f43 (Да, я знаю, что его изменение на static устранит эту проблему)

+0

Обратите внимание, что передача 'mymy' в' Base' является неопределенным поведением, так как она не инициализирована. – TartanLlama

ответ

4

Стандарт говорит, что (§ 12.6.2/10 , выделено мной):

Если данный нестатическая элемент данных имеет как инициализатор член по умолчанию и MEM-инициализатору, инициализация , указанная mem-initializer, и инициализатор элемента нестатического элемента данных игнорируется. [Пример: Учитывая

struct A { 
     int i = /* some integer expression with side effects */ ; 
     A(int arg) : i(arg) { } 
     // ... 
}; 

A(int) конструктор просто инициализирует i к значению arg, и побочные эффекты в инициализаторе член i «s по умолчанию не будет иметь место. -end примера]

http://coliru.stacked-crooked.com/ использование г ++, который не производит предупреждение, но результат тот же: Base не инициализирован с 50 или 23, но с 0. Вы можете получить страннее поведение, добавив еще один атрибут перед тем mymy:

class Derived: public Base { 
    public: 
    Derived() : Base(mymy), mymymy(mymy), mymy(23) { 
     std::cout << "Derived:" << mymy << std::endl; 
     std::cout << "Derived:" << mymymy << std::endl; 

    } 
    int mymymy; 
    const int mymy = 50; 
}; 

Выход из coliru:

Base:4197208 
Derived:23 
Derived:4197208 
Main:23 

Но если добавить атрибут после mymy:

class Derived : public Base { 
    public: 
    Derived() : Base(mymy), mymy(23) { 
     std::cout << "Derived:" << mymy << std::endl; 
     std::cout << "Derived:" << mymymy << std::endl; 

    } 
    const int mymy = 50; 
    int mymymy= mymy; 

}; 

Значение вы предоставляете в члене-инициализаторе-списке конструктора будет использоваться:

Base:0 
Derived:23 
Derived:23 
Main:23 

Что касается const квалификации: Вы всегда можете инициализировать const член в член-список-инициализаторе вашего конструктора (это единственное место, где вы можете инициализировать их вместе с инициализаторах членов по умолчанию).

Я не знаю, если есть более явная цитата из стандарта, но § 12.6.2/7 (пример довольно четко, хотя):

список_выражений или braced-init-list in mem-initializer используется для инициализации указанного подобъекта (или, в случае конструктора-делегата, полного объекта класса) в соответствии с правилами инициализации 8.5 для прямой инициализации , [Пример:

struct B1 { B1(int); /* ... */ }; 
struct B2 { B2(int); /* ... */ }; 
struct D : B1, B2 { 
    D(int); 
    B1 b; 
    const int c; 
}; 
D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) 
    { /* ... */ } 
D d(10); 

-end пример]


Последнее C++ проект стандарта 17 (N4594).

3

Если вы используете инициализатор ctor, то в инициализации класса игнорируется.

Примите во внимание, что вызов базового конструктора с аргументом mymy

Derived() : Base(mymy), mymy(23) {std::cout << "Derived:" << mymy << std::endl;} 

неверен, потому что члены данных производного класса еще не были инициализированы.

+0

Не могли бы вы сослаться на это, в стандарте? – fritzone

+0

Но как насчет 'const'? Должен ли компилятор жаловаться? – fritzone

+0

@fritzone К сожалению, у меня нет доступа к Стандарту сейчас. Что касается спецификатора const, то ctor также инициализирует постоянные члены данных (кроме статических элементов данных). –

Смежные вопросы