Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.54/13: Рейтинг темы: голосов - 13, средняя оценка - 4.54
734 / 339 / 70
Регистрация: 10.06.2014
Сообщений: 2,356
1

Не удается присвоить значение статическому полю класса

29.02.2016, 20:38. Просмотров 2432. Ответов 21
Метки нет (Все метки)

Почему данный код не работает?
Выводит ошибку Error LNK2001 неразрешенный внешний символ ""public: static int Test::total" (?total@Test@@2HA)"
Пользуюсь Visual Studio Express 2015 под Windows 7 32 bit

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
class Test
{
public:
    static int total;
};
 
int main()
{
    Test::total = 10;
    cout << Test::total;
    return 0;
}
Ещё огорчает то, что компилятор выдает ошибки на Русском. Как сменить на Английский?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.02.2016, 20:38
Ответы с готовыми решениями:

Присвоить значение к полю класса
В одном месте я получаю всех полей класса вот так: Field fields = this.getClass().getFields(); ...

Присвоить значение NumericUpDown.Value полю класса
Почему я не могу созданному полю присвоить значение NumericUpDown? Логически ведь можно, а не...

как задать значение статическому элементу класса
В классе есть статический Private элемент, мне нужно создать статическую функцию которая будет...

Присвоить $_FILES полю класса
Здравствуйте, подскажите как присвоить полю класса файл class Files { public $file1;...

21
Хитрая блондиночка $)
1460 / 974 / 399
Регистрация: 21.12.2015
Сообщений: 3,785
29.02.2016, 20:46 2
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// и.cpp: определяет точку входа для консольного приложения.
//
 
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
class Test
{
public:
    static int total;
};
 
int Test::total = 10;
int _tmain(int argc, _TCHAR* argv[])
{
    cout << Test::total;
    return 0;
}
Но будет лучше, если ты расскажешь для чего тебе это поле и какую роль оно должно играть.
1
51 / 51 / 24
Регистрация: 24.12.2011
Сообщений: 133
29.02.2016, 20:51 3
Внутри класса происходит объявление (decalration) статического члена класса, но не определение (definition), то есть класс просто знает о существовании такой переменной. Определение нужно сделать отдельно. Вот так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
class Test
{
public:
    static int total;
};
 
int Test::total;
 
int main()
{
    Test::total = 10;
    cout << Test::total;
    return 0;
}
0
734 / 339 / 70
Регистрация: 10.06.2014
Сообщений: 2,356
29.02.2016, 20:53  [ТС] 4
Hikari,
Спасибо. Но логику не понял. Сначала объявили статическое свойство как int, затем присваиваем ему значение.
Есть 2 вопроса. 1) Зачем снова писать int, тут int Test::total = 10; если мы уже выше сказали что это int, могут быть другие варианты? 2) Почему нельзя статическому полю задать значение по умолчанию?

Цитата Сообщение от Hikari Посмотреть сообщение
Но будет лучше, если ты расскажешь для чего тебе это поле и какую роль оно должно играть.
Я изучаю синтаксис и возможности языка)

Добавлено через 39 секунд
Juffin,
Внутри класса тоже можно задать значение точно так же
0
51 / 51 / 24
Регистрация: 24.12.2011
Сообщений: 133
29.02.2016, 20:59 5
sys_beginner, в каком смысле? Присвоить что-нибудь статическому полю класса?
0
734 / 339 / 70
Регистрация: 10.06.2014
Сообщений: 2,356
29.02.2016, 21:04  [ТС] 6
Juffin, Забудьте я ошибся. А почему в классе нельзя присвоить? Какая разница, в классе или вне класса? Интересен смысл
0
51 / 51 / 24
Регистрация: 24.12.2011
Сообщений: 133
29.02.2016, 21:09 7
sys_beginner, разница в том, что нужно сначала объявить это статическое поле:
C++
1
int Test::total;
До этого переменная еще не объявлена, и поэтому линкер (именно линкер, а не компилятор, с точки зрения компилятора всё в порядке) не может её найти и выдает ошибку.

После этого хоть в классе, хоть не в классе. Вот так, например, делать можно:
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
#include <iostream>
 
using namespace std;
 
class Test
{
public:
    static int total;
    
    void Assign()
    {
        Test::total = 1;
    }
};
 
int Test::total;
 
int main()
{
    Test T;
    T.Assign();
    T.total += 1;
    Test::total += 1;
    
    cout << Test::total;
    return 0;
}
---

А, понял, в чём вопрос. Логика в том, что статическая переменнная - это как-бы не член класса. Она в каком-то смысле висит отдельно от экземпляров класса.
1
734 / 339 / 70
Регистрация: 10.06.2014
Сообщений: 2,356
29.02.2016, 21:30  [ТС] 8
Juffin,
Линкер? Почитаю про него, прежде не слышал о нем. Спасибо за новую информацию.

Цитата Сообщение от Juffin Посмотреть сообщение
До этого переменная еще не объявлена
Интересно. В классе же объявлено поле к которому происходит обращение. Не могу понять, зачем два раза писать почти одно и то же, причем второй раз вне класса.
Почему в классе нельзя просто написать static int total = 10; ? Так же проще было бы.
Когда объявляется обычная переменная можно ведь сразу задать ей значение например int x = 10; а в классе почему то нельзя

Особенно не ясно то, почему компилируется такой код
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
class Test
{
public:
    int getX() const
    {
        return x;
    }
private:
    static int x;
};
int Test::x = 20;
int main()
{
    Test t;
    cout << t.getX();//выводит 20
    return 0;
}
Каким образом полю x из вне было присвоено значение 20? Оно ведь приватное. Никак не пойму
0
51 / 51 / 24
Регистрация: 24.12.2011
Сообщений: 133
29.02.2016, 21:52 9
Лучший ответ Сообщение было отмечено Undisputed как решение

Решение

sys_beginner, когда внутри класса ты пишешь
C++
1
static int x;
то ты сообщаешь компилятору, что такая переменная будет существовать, но не создаешь её. Это называется declaration.
Когда ты потом пишешь
C++
1
int Test::x;
ты объявляешь переменную, для неё выделяется память, и это называется definition.
Если ты пишешь
C++
1
int Test::x = 20;
то это объявление и инициализация, и её можно делать даже для приватных статических полей. Это не обращение извне, а объявление. Позже в коде напрямую к нему уже нельзя будет обращаться.

Почему нельзя объявлять и инициализировать статические переменные внутри класса? Потому, что инициализация полей происходит при создании каждого экземпляра класса, а статические поля существуют как бы отдельно и инициализируются только один раз.
0
Хитрая блондиночка $)
1460 / 974 / 399
Регистрация: 21.12.2015
Сообщений: 3,785
29.02.2016, 22:08 10
Цитата Сообщение от sys_beginner Посмотреть сообщение
Оно ведь приватное.
https://msdn.microsoft.com/ru-... 6w579.aspx
При объявлении данных-члена в объявлении класса ключевое слово static указывает, что всеми экземплярами этого класса совместно используется одна копия этого члена.Статические данные-член должны быть определены в области видимости файла.Целочисленные данные-член, объявляемые как conststatic, могут иметь инициализатор.
Наверное поэтому.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Test
{
private:
    static int total;
public:
    static int tot(){return total;};
};
 
int Test::total = 666;
int _tmain(int argc, _TCHAR* argv[])
{
    cout << Test::tot();
    return 0;
}
0
734 / 339 / 70
Регистрация: 10.06.2014
Сообщений: 2,356
29.02.2016, 22:13  [ТС] 11
Цитата Сообщение от Juffin Посмотреть сообщение
то ты сообщаешь компилятору, что такая переменная будет существовать, но не создаешь её
Теперь логика ясна, спасибо!
Дополнительный вопрос отпал, девушка выше протицировала истину)

Добавлено через 4 минуты
Hikari, о, спасибо, не знал что с const можно задавать значение по умолчанию.
А почему у тебя main объявляется как _tmain? Это нестандартный компилятор?
0
1 / 1 / 2
Регистрация: 25.05.2015
Сообщений: 32
29.02.2016, 22:50 12
#include "stdafx.h"
ну, указанием #include "stdafx.h" ты сам показал, что используешь MicroSoft компайлеры. А стандартные они, и насколько - это холивар.
0
734 / 339 / 70
Регистрация: 10.06.2014
Сообщений: 2,356
29.02.2016, 22:56  [ТС] 13
basileus, basileus,
А без этого включения программа не компилируется. Значит под Windows такое включение обязательно?
Цитата Сообщение от basileus Посмотреть сообщение
А стандартные они, и насколько - это холивар
Почему? В С++ разве нету определенного стандарта, прочитав который можно завершить этот спор?
0
С чаем беда...
Эксперт CЭксперт С++
7874 / 3800 / 1044
Регистрация: 18.10.2014
Сообщений: 8,076
29.02.2016, 23:11 14
Цитата Сообщение от sys_beginner Посмотреть сообщение
1) Зачем снова писать int, тут int Test::total = 10; если мы уже выше сказали что это int, могут быть другие варианты?
Так устроен язык С++ (как, впрочем и С). Объявление переменной должно содержать спецификатор типа. Даже если вы сто раз объявляете одну и ту же переменную, спецификатор типа придется писать каждый раз.

Цитата Сообщение от sys_beginner Посмотреть сообщение
Почему нельзя статическому полю задать значение по умолчанию?
Что такое "значение по-умолчанию"?

Во-первых, у переменной типа 'int' со статическим классом памяти есть "значение по-умолчанию" - это ноль. Ваша переменная изначально гарантированно инициализируется нулем.

Во-вторых, в определении вашей статической переменной вы можете указать свой инициализатор, как вы сами написали 'int Test::total = 10;'.

Цитата Сообщение от sys_beginner Посмотреть сообщение
Внутри класса тоже можно задать значение точно так же
"Внутри класса" можно задавать инициализаторы для нестатических членов класса (начиная с С++11), а также для статических целочисленных константных членов (можно было всегда).

Данный случай ни под одну из этих категорий не попадает. Поэтому "внутри класса" - нельзя.
0
734 / 339 / 70
Регистрация: 10.06.2014
Сообщений: 2,356
29.02.2016, 23:26  [ТС] 15
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Что такое "значение по-умолчанию"?
Имелось ввиду присвоение значения в момент объявления
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Ваша переменная изначально гарантированно инициализируется нулем.
Да но хотелось бы что бы в классе можно было. Мыслить проще, если все что касается класса, можно инициализировать в его пределах.
0
С чаем беда...
Эксперт CЭксперт С++
7874 / 3800 / 1044
Регистрация: 18.10.2014
Сообщений: 8,076
29.02.2016, 23:53 16
Цитата Сообщение от sys_beginner Посмотреть сообщение
Имелось ввиду присвоение значения в момент объявления
Ну, условно выражаясь, инициализаторы в языке С++ традиционно являются атрибутом определения, а не объявления. В классическом С++ (С++98) и С, как только в объявлении появлялся инициализатор, это объявление становилось определением.

Исключение из этого принципа было сделано только для целочисленных статических констант, ибо они играют особую роль в языке. В С++11 появилось еще одно "исключение" - для нестатических членов можно указывать инициализаторы, которые потом будут использоваться при генерации инициализаторов в конструкторах.

Т.е. все эти исключения из вышеупомянутого принципа вводились по какой-то конкретной причине. Для неконстантных и/или нецелочисленных статических членов класса такой причины пока не нашлось.
1
nd2
3399 / 2781 / 1250
Регистрация: 29.01.2016
Сообщений: 9,423
01.03.2016, 01:00 17
Цитата Сообщение от sys_beginner Посмотреть сообщение
А без этого включения программа не компилируется.
Без #include "stdafx.h"? В настройках проекта (или при создании) это всё можно отключить, и будет компилироваться.
Цитата Сообщение от sys_beginner Посмотреть сообщение
В С++ разве нету определенного стандарта, прочитав который можно завершить этот спор?
Есть. По стандарту, о main():
§ 3.6.1 Main function
1. A program shall contain a global function called main, which is the designated start of the program. It
is implementation-defined whether a program in a freestanding environment is required to define a main
function. [ Note: In a freestanding environment, start-up and termination is implementation-defined; startup
contains the execution of constructors for objects of namespace scope with static storage duration;
termination contains the execution of destructors for objects with static storage duration. —end note ]

2. An implementation shall not predefine the main function. This function shall not be overloaded. It shall
have a return type of type int, but otherwise its type is implementation-defined. All implementations shall
allow both
— a function of () returning int and
— a function of (int, pointer to pointer to char) returning int
as the type of main (8.3.5). In the latter form, for purposes of exposition, the first function parameter is
called argc and the second function parameter is called argv, where argc shall be the number of arguments
passed to the program from the environment in which the program is run. If argc is nonzero these arguments
shall be supplied in argv[0] through argv[argc-1] as pointers to the initial characters of null-terminated
multibyte strings (ntmbs s) (17.5.2.1.4.2) and argv[0] shall be the pointer to the initial character of a
ntmbs that represents the name used to invoke the program or "". The value of argc shall be non-negative.
The value of argv[argc] shall be 0. [ Note: It is recommended that any further (optional) parameters be
added after argv. —end note ]

3. The function main shall not be used within a program. The linkage (3.5) of main is implementation-defined.
A program that defines main as deleted or that declares main to be inline, static, or constexpr is illformed.
The name main is not otherwise reserved. [ Example: member functions, classes, and enumerations
can be called main, as can entities in other namespaces. —end example ]

4. Terminating the program without leaving the current block (e.g., by calling the function std::exit(int)
(18.5)) does not destroy any objects with automatic storage duration (12.4). If std::exit is called to
end a program during the destruction of an object with static or thread storage duration, the program has
undefined behavior.

5. A return statement in main has the effect of leaving the main function (destroying any objects with automatic
storage duration) and calling std::exit with the return value as the argument. If control reaches the end
of main without encountering a return statement, the effect is that of executing
return 0;
Цитата Сообщение от sys_beginner Посмотреть сообщение
А почему у тебя main объявляется как _tmain? Это нестандартный компилятор?
Придумка microsoft, нестандартное расширение, а потому - непереносимое.
0
С чаем беда...
Эксперт CЭксперт С++
7874 / 3800 / 1044
Регистрация: 18.10.2014
Сообщений: 8,076
01.03.2016, 03:02 18
Цитата Сообщение от nd2 Посмотреть сообщение
Придумка microsoft, нестандартное расширение, а потому - непереносимое.
Если уж на то пошло, '_tmain' - это просто макрос, за которым скрывается либо 'main', либо 'wmain'. Так что рассуждать о стандартности или нестандартности именно '_tmain' нет смысла. Ничего нетстандартного в '_tmain', как таковом, нет. Также и вы в своем коде можете сделать '#define cactus main' и объявлять стартовую функцию программы как 'int cactus()`.

Нестандартной тут является функция 'wmain', а это уже другая история.
1
nd2
3399 / 2781 / 1250
Регистрация: 29.01.2016
Сообщений: 9,423
01.03.2016, 04:17 19
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если уж на то пошло, '_tmain' - это просто макрос, за которым скрывается либо 'main', либо 'wmain'. Так что рассуждать о стандартности или нестандартности именно '_tmain' нет смысла. Ничего нетстандартного в '_tmain', как таковом, нет.
Да, неправильно написал, и, в общем-то, переносимо, нужно только tchar.h подключать.
0
Хитрая блондиночка $)
1460 / 974 / 399
Регистрация: 21.12.2015
Сообщений: 3,785
02.03.2016, 16:31 20
Цитата Сообщение от sys_beginner Посмотреть сообщение
А почему у тебя main объявляется как _tmain? Это нестандартный компилятор?
Обычный Vs 2010 экспресс...
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
02.03.2016, 16:31

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

Как полю класса типа char* присвоить значение типа *char
Проблема в строчке 46 (не пинайте сильно за формат кода и за говнокод) #include &quot;stdafx.h&quot; ...

Присвоить значение полю в отчете
Здравствуйте Вам , о мудрые головы форума!! Помогите, плиZ !:cry: Сказываются многочасовые...

Как присвоить значение полю
Доброго времени суток уважаемые форумчане. Помогите разобраться. Мне необходимо присвоить полю (в...

Как присвоить полю значение из запроса?
Выдает ошибку &quot;Invalid use of property&quot; Dim rst As DAO.Recordset Dim sSQL As String sSQL =...


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

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

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