Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 29, средняя оценка - 4.66
_Cherep_
1 / 1 / 0
Регистрация: 02.08.2012
Сообщений: 15
#1

Отличие объявления, определения и инициализации - C++

26.06.2013, 23:57. Просмотров 4541. Ответов 42
Метки нет (Все метки)

Здравствуйте, товарищи.

Читаю тут книжицу по C++, учусь потихоньку.
И возник у меня вопрос нерядового характера: в чём фундаментальное отличие объявления, определения и инициализации? В книге всё намешано, ничего не понятненько.

Однако усёк, что они говаривают, будто такая строка:
C++
1
int a = 3;
не просто присваивание переменной значения, а что-то большее.
И как-то это связано с созданием экземпляров классов.

А ещё пишут, что есть инициализация прямая и инициализация копии.
А потом вот это кажут:
C++
1
2
int val = 1024;
int val (1024);
И говаривают, будто val в обоих случаях будет одинаковой.

Что-то я видно не секу истинной сути.
Помогите словцом мудрым.
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.06.2013, 23:57
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Отличие объявления, определения и инициализации (C++):

Правила объявления инициализации - C++
Напишите основные - самые главные правила обьявления инициализации.

В чём отличие разных способов объявления переменных? - C++
в чем отличие int a(2); от int a=2; И как писать правильней

Архитектура правильного определения и объявления класса - C++
Всем привет! В процессе написания одной программы "поймал" себя на том, что видимо не до конца понимаю логику правильного определения...

Циклы for. Проблема объявления/инициализации - C++
Эх, так и придется создавать новую тему. А то, блин, интересно ж... Итак, я тут в недавней теме утверждал, что блок инициализации цикла...

объявления - C++
в чем отличие такого определения float var = 1.f; от такого float var = 1.0f;

Объявления массива. - C++
Как увеличить количество переменных в массиве?

42
Croessmah
Эксперт CЭксперт С++
13508 / 7666 / 866
Регистрация: 27.09.2012
Сообщений: 18,864
Записей в блоге: 3
Завершенные тесты: 1
27.06.2013, 15:54 #31
Если вспомнить книгу Макконнелла, то если переменной при создании не задается значение и она содержит мусор, то это неверная инициализация
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6503 / 3139 / 307
Регистрация: 04.12.2011
Сообщений: 8,661
Записей в блоге: 5
27.06.2013, 16:23 #32
Цитата Сообщение от Croessmah Посмотреть сообщение
неверная инициализация
Неверных инициализаций не бывает. То есть взаимно это как-то.
Вообще, для новичка такие вещи как объявление, определение и инициализация, - предварительное объявление, как и многое другое. Нельзя язык учить как букварь, многое можно понять значительно позже ознакомления.
@_Cherep_, объявление это информация для компилятора для формирования кода. С местом объявления связаны: время жизни, видимости, действия переменной, например.
Определение - информация компилятору и редактору связей для конкретизации значения или адреса.
Инициализация - совмещение, того и другого. Тема большая. Вам пока достаточно понять, что константы и ссылки, невозможно объявить без инициализации. А уж как работают конструктора при инициализации или присваивании это лучше читать и спрашивать конкретно.
0
Catstail
Модератор
22711 / 11080 / 1795
Регистрация: 12.02.2012
Сообщений: 18,268
27.06.2013, 16:47 #33
В C++ есть такие понятия:

1) объявление (декларация)
2) определение (дефиниция)

Пояснить что есть что, проще всего на примере функций:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
int F1(int a);
{
    int i,j;
    ...
    j=F2(i);
 
    return ...
}
 
int F2 (int x)
{
 ...
}

Этот код не скомпилируется, т.к. в момент компиляции F1 компилятор ничего не знает про F2.
Чтобы код скомпилировался, функцию F2 нужно предварительно объявить (декларировать):

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int F2(int);  // Декларация F2
 
int F1(int a);
{
    int i,j;
    ...
    j=F2(i);
 
    return ...
}
 
int F2 (int x)  // Дефиниция F2 (определение)
{
 ...
}
Другой вариант: разместить определение F2 перед F1:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
int F2 (int x)  // Дефиниция F2 (определение)
{
 ...
}
 
int F1(int a);
{
    int i,j;
    ...
    j=F2(i);
 
    return ...
}
Теперь декларация не нужна (поскольку всякая дефиниция является одновременно и декларацией).

Ну, а инициализация - это присвоение объекту или переменной некоего значения в момент создания.
1
Croessmah
Эксперт CЭксперт С++
13508 / 7666 / 866
Регистрация: 27.09.2012
Сообщений: 18,864
Записей в блоге: 3
Завершенные тесты: 1
27.06.2013, 16:47 #34
@IGPIGP, Откопал у Макконнелла
Неверная инициализация данных - один из плодородных источников ошибок в программировании. Эффективные способы предотвращения проблем с инициализацией могут значительно ускорить отладку.
При неверной инициализации проблемы объясняются тем, что переменная имеет не то первоначальное значение, которое вы ожидаете. Это может случиться по одной из следующих причин.
- Переменной не было присвоено значения. Она имеет то случайное значение, которое находилось в соответствующих ячейках памяти при запуске программы.
- Значение переменной устарело. Когда-то переменной было присвоено значение, но оно утратило свою актуальность.
- Одним частям переменной были присвоены значения, а другим нет.
1
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6503 / 3139 / 307
Регистрация: 04.12.2011
Сообщений: 8,661
Записей в блоге: 5
27.06.2013, 17:43 #35
Цитата Сообщение от Croessmah Посмотреть сообщение
Неверная инициализация данных - один из плодородных источников ошибок в программировании.
Это правда. Тем не менее может же быть случай когда переменная должна быть объявлена и не может быть проинициализирована полностью. Например если классы связны указателями друг на друга.
Новичку это ненужно. :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <string>
#include <typeinfo.h>
using namespace std;
class A {
int a;
double b;
string c;
public:
    A()
        :a(1), b(2.0), c("a anb b were sitting on a pipe")  
    {}
A(int a_)//частично инициализирует
:a(a_)
{}
A(double b_)//частично инициализирует
:b(b_)
{}
A(string c_)//частично инициализирует
:c(c_)
{}
A(const A& orig)//копирующий (и полностью инициализирующий)
:a(orig.a), b(orig.b), c(orig.c)
{}
    int& propertyA(){
return a;
}
    double& propertyB(){
return b;
}
string& propertyC(){
return c;
}
};
int main()
 {
     A *b=new A;//динамическая память выделена но не инициализирована
     cout<<b->propertyA()<<endl;//мусор если конструктор по умолчанию (без параметров) закоментирован
 
     A a;//память на стеке выделена
     cout<<a.propertyA()<<endl;////мусор если конструктор закоментирован
     a.propertyA()=2;// заполняется простым присваиванием
     a.propertyB()=5.0;// заполняется простым присваиванием
     a.propertyC()="a+b= ";// заполняется простым присваиванием
     
     cout<<a.propertyA()<<endl;
     cout<<a.propertyB()<<endl;
     cout<<a.propertyC()<<a.propertyA()+a.propertyB()<<endl;
 
     A c(a);//A c = a; - аналогично, полноценность инициализации определяется полноценность конструктора копии
 
     cout<<c.propertyA()<<endl;
     cout<<c.propertyB()<<endl;
     cout<<c.propertyC()<<a.propertyA()+a.propertyB()<<endl;
 
     A d = "Oi scolco musora budet esli razremite stroki nige...";//работает конструктор преобразования принимающий строку
     //остальные поля не инициализированы
     //отложенную, частичную инициализацию можно использовать для связывания двух экземпляров классов, когда
     //один из них обявлен опережающим объявлением, но не может быть полностью инициализирован без указателя на
     //второй, а второму для создания экземпляра нужен указатель на первый
     //такую штуку (создание пары связянных объектов разных классов можно описать в глобальном или статическом методе
     //или написать для этого отдельный класс.
     cout<<d.propertyC()<<endl;
     //cout<<d.propertyA()<<endl;
     //cout<<d.propertyB()<<endl;
     system("pause");
     }
0
Tulosba
:)
Эксперт С++
4396 / 3232 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
27.06.2013, 17:49 #36
Цитата Сообщение от IGPIGP Посмотреть сообщение
Например если классы связны указателями друг на друга.
В таком случае следует инициализировать неким нулевым значением, которое будет четко говорить, что поле не инициализировано. А не оставлять его в "мусорном" состоянии. Например должно быть как минимум так:
C++
1
2
3
A(int a_)//частично инициализирует
:a(a_), b(0) // c - не нужно, т.к. std::string инициализируется конструктором по умолчанию
{}
1
Croessmah
Эксперт CЭксперт С++
13508 / 7666 / 866
Регистрация: 27.09.2012
Сообщений: 18,864
Записей в блоге: 3
Завершенные тесты: 1
27.06.2013, 17:55 #37
Не нужно новичку?
Да ТС, наверное, уже в шоке от всей нашей писанины
1
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6503 / 3139 / 307
Регистрация: 04.12.2011
Сообщений: 8,661
Записей в блоге: 5
27.06.2013, 18:01 #38
Цитата Сообщение от Tulosba Посмотреть сообщение
В таком случае следует инициализировать неким нулевым значением,
Может и правда. А если, ход выполнения одного из методов инициализации зависим от значения поля? Или поле - файловый поток, например?
Конечно если слить такие классы в один, то такой вопрос обходится, а если не нет? У меня маловато опыта, чтобы сказать определённо.

Добавлено через 4 минуты
Цитата Сообщение от Croessmah Посмотреть сообщение
Да ТС, наверное, уже в шоке от всей нашей писанины
Не может быть. Сейчас заметил: в заголовке typeinfo,h забыл удалить и вообще сырой кусок.
0
Tulosba
:)
Эксперт С++
4396 / 3232 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
27.06.2013, 18:03 #39
Цитата Сообщение от IGPIGP Посмотреть сообщение
А если, ход выполнения одного из методов инициализации зависим от значения поля?
Ради бога. Пусть зависит. Главное чтобы объект был в согласованном состоянии, т.е. сохранятся инвариант класса.
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6503 / 3139 / 307
Регистрация: 04.12.2011
Сообщений: 8,661
Записей в блоге: 5
27.06.2013, 18:39 #40
Цитата Сообщение от Tulosba Посмотреть сообщение
Главное чтобы объект был в согласованном состоянии, т.е. сохранятся инвариант класса.
Это безопаснее конечно, но немного дольше. Разве нет?
0
Tulosba
:)
Эксперт С++
4396 / 3232 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
27.06.2013, 19:00 #41
Цитата Сообщение от IGPIGP Посмотреть сообщение
Это безопаснее конечно, но немного дольше. Разве нет?
По сравнению с чем? Приведите примеры если не затруднит.
0
_Cherep_
1 / 1 / 0
Регистрация: 02.08.2012
Сообщений: 15
27.06.2013, 23:38  [ТС] #42
Ну и холивар я своим вопросом поднял
Товарищам @IGPIGP и @Catstail отдельное спасибо!
1
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6503 / 3139 / 307
Регистрация: 04.12.2011
Сообщений: 8,661
Записей в блоге: 5
28.06.2013, 01:58 #43
Цитата Сообщение от _Cherep_ Посмотреть сообщение
Ну и холивар я своим вопросом поднял
"_Cherep_, я уверен был, что никак не мог Вас обидеть.

Не по теме:

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

0
28.06.2013, 01:58
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
28.06.2013, 01:58
Привет! Вот еще темы с ответами:

Объявления классов - C++
Класс может быть объявлен так: class MyClass { ... }; а может быть объявлен и так typedef class

Ошибки объявления - C++
Stack.h #pragma once class Stack { public: void push (StackPtr *,int); int pop(StackPtr*); int isEmpty(StackPtr);

Вылетает из-за объявления указателя - C++
Unhandled exception at 0x010C3A8D in game_1.exe: 0xC0000005: Access violation reading location 0xCDCDCDCD. Source.cpp: ...

Особенность объявления функции - C++
Собсно вопрос такой , зачем нужно объявлять функции если их можно просто определять? связано ли это с компилятором?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
43
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru