Зачем?Неявная инициализация от неинициализированных родительских членов класса - PullRequest
0 голосов
/ 21 июня 2010

У меня был неприятный опыт инициализации C ++, и я пытаюсь увидеть, есть ли пример из реальной жизни, который не оправдывает никаких предупреждений от компилятора.

Следующий код компилируется правильно, но foo и bar инициализируются значениями uninit (я полагаю из неинициализированного родительского класса). Компиляторы, как g ++, так и VS, не выдают никаких предупреждений. Мне, конечно, сказали, что это плохое поведение - оставлять участников публичными и не украшать их. Тем не менее, я предполагаю, что компилятор может обнаружить такую ​​несогласованность и, по крайней мере, выдать предупреждение на самых высоких уровнях предупреждения, потому что я не вижу никаких приложений такого рода кода.

#include <iostream>
using namespace std;

class base_class {
    public:
        int foo;
        int bar;

    base_class(int foo,int bar):
        foo(foo),bar(bar) 
    {}
};

class derived_class: public base_class {
    public:
    derived_class(int Foo, int Bar):
        base_class(foo,bar)
    { 
                    int a = Foo * Bar;

                    a++;
                    cout << foo << " " << bar << endl;
    }
};

int main ()
{
    derived_class *buzz = new derived_class(1,2);
    buzz->print();
}

Ответы [ 5 ]

1 голос
/ 21 июня 2010

Ваш обновленный код показывает вашу проблему:

В строке 17 вы используете foo и bar из base_class для вызова конструктора base_class со значениями, которые к тому времени не были инициализированы.Результатом является неопределенное поведение и, следовательно, странные значения.Как сказал Майк: вы получаете предупреждение только при включенной оптимизации, что довольно странно.

1 голос
/ 21 июня 2010

Я думаю, что ваша проблема в том, что у вас есть параметры конструктора с заглавными буквами:

С помощью следующего кода я получаю правильные значения:

#include <iostream>
using namespace std;

class base_class {
    public:
        int foo;
        int bar;

    base_class(int foo,int bar):
        foo(foo),bar(bar)
        {
        int a = foo * bar;

        a++;

        cout << "Base : " << foo << ", " << bar << ", " << a << endl;
    }

};

class derived_class: public base_class {
    public:
    derived_class(int foo, int bar):
        base_class(foo,bar)
    {
        cout << "derived : " << foo << ", " << bar << endl;
    }
};

int main ()
{
    derived_class baz(1,2);
}

Выход:

Base : 1, 2, 3
derived : 1, 2

В таком случае происходит то, что ваши члены "инициализируются" с вашими значениями неинициализированных членов:)

my2c

0 голосов
/ 21 июня 2010

Я думаю, что вы не компилируете со всеми активированными предупреждениями (и вы действительно должны).Например, в вашем коде вот вывод из g ++:

g++ -O3 -W -Wall    init.cc   -o init
init.cc: In function ‘int main()’:
init.cc:22: warning: ‘baz.derived_class::<anonymous>.base_class::foo’ is used uninitialized in this function
init.cc:28: note: ‘baz.derived_class::<anonymous>.base_class::foo’ was declared here
init.cc:22: warning: ‘baz.derived_class::<anonymous>.base_class::bar’ is used uninitialized in this function
init.cc:28: note: ‘baz.derived_class::<anonymous>.base_class::bar’ was declared here

Вы заметите -W -Wall для обеспечения максимального количества предупреждений.В противном случае, как указывалось ранее, ошибка используется в случае инициализации переменной.

0 голосов
/ 21 июня 2010

Анализ, необходимый для предупреждения об использовании неинициализированных переменных во время компиляции, довольно сложен, и кажется, что GCC делает это только при включенной оптимизации. Предположительно кто-то думал, что это недопустимо замедляет неоптимизирующую сборку.

Компиляция вашего кода с помощью g++ -Wall -O выдает предупреждения. Я не могу комментировать Visual Studio.

0 голосов
/ 21 июня 2010

Это:

#include <iostream>

class base_class {
public:
    int foo;
    int bar;
    base_class(int foo,int bar) : foo(foo),bar(bar) {}
};

class derived_class : public base_class {
public:
    derived_class(int foo, int bar) : base_class(foo,bar) {}
};

int main ()
{
    derived_class baz(1,2);
    std::cout << baz.foo << ", " << baz.bar << '\n';
    return 0;
}

прекрасно компилируется для меня с использованием VC9 и VC10 и пишет 1, 2 в обоих случаях. Вы получаете что-нибудь еще?

Обратите внимание, однако, что присвоение имен переменным-членам и параметрам конструктора обязательно приведет к путанице.

Стандартный отказ от ответственности: за исключением глупых примеров, подобных этому, никогда не используйте public данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...