Error making static c

I have a class definition with a virtual method. On compiling I get the error that 'MethodType Class::Method' is not a static member of class Class The most popular solution I have found is to a...

I have a class definition with a virtual method.

On compiling I get the error that 'MethodType Class::Method' is not a static member of class Class

The most popular solution I have found is to add the keyword static to the Method definition in the header file.

However, the method is defined as virtual. So to add the static keyword I will have to remove the virtual keyword. Unfortunately that cannot be done as the class inherits from a parent where this method is also declared virtual, leading to another compiler error. (Please note, I’m using defined interfaces and have no access to the parent class’s source code)

Does anyone have any ideas?


Header file:

class X : public OtherClass
{
   public:
      X();
      ~X();  

     virtual structType MethodName(ParamType1,ParamType2);

};

Then in the CPP file I have:

structType * X::MethodName(ParamType1 P1, ParamType2 P2)
{
   //Implementation here
}

And that gets flagged with error:

'structType* X::MethodName' is not a static member of 'class X'

Содержание

  1. Пока смерть не разлучит нас или всё о static в C++
  2. Что такое static?
  3. Где используется?
  4. Статические переменные внутри функции
  5. Статические объекты класса
  6. Статические члены класса
  7. Статические функции
  8. Статические функции-члены класса (методы)
  9. Заключение
  10. Пока смерть не разлучит нас или всё о static в C++
  11. Что такое static?
  12. Где используется?
  13. Статические переменные внутри функции
  14. Статические объекты класса
  15. Статические члены класса
  16. Статические функции
  17. Статические функции-члены класса (методы)
  18. Заключение

Пока смерть не разлучит нас или всё о static в C++

Всем привет. На одном из код-ревью я столкнулся с мыслью, что многие, а чего скрывать и я сам, не то чтобы хорошо понимаем когда нужно использовать ключевое слова static. В данной статье я хотел бы поделиться своими знаниями и информацией по поводу ключевого слова static. Статья будет полезна как начинающим программистам, так и людям, работающим с языком С++. Для понимания статьи у вас должны быть знания о процессе сборки проектов и владение языком С/С++ на базовом уровне. Кстати, static используется не только в С++, но и в С. В этой статье я буду говорить о С++, но имейте в виду, что всё то, что не связано с объектами и классами, в основном применимо и к языку С.

Что такое static?

Static — это ключевое слово в C++, используемое для придания элементу особых характеристик. Для статических элементов выделение памяти происходит только один раз и существуют эти элементы до завершения программы. Хранятся все эти элементы не в heap и не на stack, а в специальных сегментах памяти, которые называются .data и .bss (зависит от того инициализированы статические данные или нет). На картинке ниже показан типичный макет программной памяти.

Где используется?

Ниже приведена схема, как и где используется static в программе.

А теперь я постараюсь детально описать все то, что изображено на схеме. Поехали!

Статические переменные внутри функции

Статические переменные при использовании внутри функции инициализируются только один раз, а затем они сохраняют свое значение. Эти статические переменные хранятся в статической области памяти (.data или .bss), а не в стеке, что позволяет хранить и использовать значение переменной на протяжении всей жизни программы. Давайте рассмотрим две почти одинаковые программы и их поведение. Отличие в них только в том, что одна использует статическую переменную, а вторая нет.

Если не использовать static в строке 4, выделение памяти и инициализация переменной count происходит при каждом вызове функции counter(), и уничтожается каждый раз, когда функция завершается. Но если мы сделаем переменную статической, после инициализации (при первом вызове функции counter()) область видимости count будет до конца функции main(), и переменная будет хранить свое значение между вызовами функции counter().

Статические объекты класса

Статический объект класса имеет такие же свойства как и обычная статическая переменная, описанная выше, т.е. хранится в .data или .bss сегменте памяти, создается на старте и уничтожается при завершении программы, и инициализируется только один раз. Инициализация объекта происходит, как и обычно — через конструктор класса. Рассмотрим пример со статическим объектом класса.

В строке 3 мы создаем класс Base с конструктором (строка 5) и деструктором (строка 8). При вызове конструктора либо деструктора мы выводим название метода класса в консоль. В строке 14 мы создаем статический объект obj класса Base. Создание этого статического объекта будет происходить только при первом вызове функции foo() в строке 18.

Из-за того, что объект статический, деструктор вызывается не при выходе из функции foo() в строке 15, а только при завершении программы, т.к. статический объект разрушается при завершении программы. Ниже приведен пример той же программы, за исключением того, что наш объект нестатический.

Если мы уберем static при создании переменной в функции foo(), то разрушение объекта будет происходить в строке 15 при каждом вызове функции. В таком случае вывод программы будет вполне ожидаемый для локальной переменной с выделенной памятью на стеке:

Статические члены класса

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

В нашем примере мы создали класс А (строка 3) и класс В (строка 9) со статическими членами класса (строка 15). Мы предполагаем, что при создании объекта b в строке 19 будет создан объект a в строке 15. Так бы и произошло, если бы мы использовали нестатические члены класса. Но вывод программы будет следующим:

Причиной такого поведения является то, что статические члены класса не инициализируются с помощью конструктора, поскольку они не зависят от инициализации объекта. Т.е. в строке 15 мы только объявляем объект, а не определяем его, так как определение должно происходить вне класса с помощью оператора разрешения области видимости (::). Давайте определим члены класса B.

Теперь, после того как мы определили наш статический член класса в строке 18, мы можем увидеть следующий результат программы:

Constructor A
Constructor B
Destructor B
Destructor A

Нужно помнить, что член класса будет один для всех экземпляров класса B, т.е. если мы создали три объекта класса B, то конструктор статического члена класса будет вызван только один раз. Вот пример того, о чем я говорю:

Constructor A
Constructor B1
Constructor B2
Constructor B3
Destructor B3
Destructor B2
Destructor B1
Destructor A

Статические функции

Статические функции пришли в С++ из С. По умолчанию все функции в С глобальные и, если вы захотите создать две функции с одинаковым именем в двух разных .c(.cpp) файлах одного проекта, то получите ошибку о том, что данная функция уже определена (fatal error LNK1169: one or more multiply defined symbols found). Ниже приведен листинг трех файлов одной программы.

Для того чтобы исправить данную проблему, одну из функций мы объявим статической. Например эту:

В этом случае вы говорите компилятору, что доступ к статическим функциям ограничен файлом, в котором они объявлены. И он имеет доступ только к функции sum() из math.cpp файла. Таким образом, используя static для функции, мы можем ограничить область видимости этой функции, и данная функция не будет видна в других файлах, если, конечно, это не заголовочный файл (.h).

Как известно, мы не можем определить функцию в заголовочном файле не сделав ее inline или static, потому что при повторном включении этого заголовочного файла мы получим такую же ошибку, как и при использовании двух функций с одинаковым именем. При определении статической функции в заголовочном файле мы даем возможность каждому файлу (.cpp), который сделает #include нашего заголовочного файла, иметь свое собственное определение этой функции. Это решает проблему, но влечет за собой увеличение размера выполняемого файла, т.к. директива include просто копирует содержимое заголовочного файла в .cpp файл.

Статические функции-члены класса (методы)

Статическую функцию-член вы можете использовать без создания объекта класса. Доступ к статическим функциям осуществляется с использованием имени класса и оператора разрешения области видимости (::). При использовании статической функции-члена есть ограничения, такие как:

  1. Внутри функции обращаться можно только к статическим членам данных, другим статическим функциям-членам и любым другим функциям извне класса.
  2. Статические функции-члены имеют область видимости класса, в котором они находятся.
  3. Вы не имеете доступа к указателю this класса, потому что мы не создаем никакого объекта для вызова этой функции.

Давайте рассмотрим следующий пример:

В классе A в строке 8 у нас есть статическая функция-член foo(). В строке 14, мы вызываем функцию используя имя класса и оператор разрешения области видимости и получаем следующий результат программы:

Из вывода видно, что никакого создания объекта нет и конструктор/деструктор не вызывается.

Если бы метод foo() был бы нестатическим, то компилятор выдал бы ошибку на выражение в строке 14, т.к. нужно создать объект для того, чтобы получить доступ к его нестатическим методам.

Заключение

В одной статье в интернете я нашел совет от автора – «Используйте static везде, где только можно». Я хотел бы написать, почему так делать не стоит, а стоит использовать только в случае необходимости.

  • Статические переменные медленнее, чем нестатические переменные. Для того, чтобы обратиться к статической переменной, нам нужно сделать несколько дополнительных действий, таких как переход в другой сегмент памяти и проверка инициализации переменной. Чаще всего, быстрее выделить локальную переменную на стеке, чем делать дополнительные действия по использованию статической переменной.
  • Если вы используете многопоточность, то здесь вы должны быть крайне осторожными, т.к. возможна ситуация, когда два и более потока захотят писать в одну статическую переменную. Если вы будете использовать нестатические переменные в функциях, то избежите подобного, т.к. для каждого потока будет создана собственная нестатическая переменная.
  • Ключевое слово static является неотъемлемой частью порождающего шаблона проектирования Singleton, который гарантирует, что будет создан только один экземпляр этого класса. В реализации этого паттерна используется и статический объект, и статическая функция-член. На практике вы можете использовать Singleton для создания объекта трейсера, логгера или любого другого объекта, который должен быть один на всё ваше приложение.
  • Иногда для того, чтобы функция отработала только один раз без хранения предыдущего состояния где-то в объекте, используют статические переменные. Пример вы можете посмотреть в разделе «Статические переменные внутри функции». Но это не очень хороший подход, и может привести к долгим часам поиска ошибки, если вы используете многопоточность.
  • На практике, программисты C++ часто используют статические функции-члены как альтернативу обычным функциям, которые не требуют создания объекта для выполнения ее.

Надеюсь, вам понравилась моя статья о ключевом слове static в языке C++. Буду рад любой критике и советам. Всем спасибо!

Источник

Пока смерть не разлучит нас или всё о static в C++

Всем привет. На одном из код-ревью я столкнулся с мыслью, что многие, а чего скрывать и я сам, не то чтобы хорошо понимаем когда нужно использовать ключевое слова static. В данной статье я хотел бы поделиться своими знаниями и информацией по поводу ключевого слова static. Статья будет полезна как начинающим программистам, так и людям, работающим с языком С++. Для понимания статьи у вас должны быть знания о процессе сборки проектов и владение языком С/С++ на базовом уровне. Кстати, static используется не только в С++, но и в С. В этой статье я буду говорить о С++, но имейте в виду, что всё то, что не связано с объектами и классами, в основном применимо и к языку С.

Что такое static?

Static — это ключевое слово в C++, используемое для придания элементу особых характеристик. Для статических элементов выделение памяти происходит только один раз и существуют эти элементы до завершения программы. Хранятся все эти элементы не в heap и не на stack, а в специальных сегментах памяти, которые называются .data и .bss (зависит от того инициализированы статические данные или нет). На картинке ниже показан типичный макет программной памяти.

Где используется?

Ниже приведена схема, как и где используется static в программе.

А теперь я постараюсь детально описать все то, что изображено на схеме. Поехали!

Статические переменные внутри функции

Статические переменные при использовании внутри функции инициализируются только один раз, а затем они сохраняют свое значение. Эти статические переменные хранятся в статической области памяти (.data или .bss), а не в стеке, что позволяет хранить и использовать значение переменной на протяжении всей жизни программы. Давайте рассмотрим две почти одинаковые программы и их поведение. Отличие в них только в том, что одна использует статическую переменную, а вторая нет.

Если не использовать static в строке 4, выделение памяти и инициализация переменной count происходит при каждом вызове функции counter(), и уничтожается каждый раз, когда функция завершается. Но если мы сделаем переменную статической, после инициализации (при первом вызове функции counter()) область видимости count будет до конца функции main(), и переменная будет хранить свое значение между вызовами функции counter().

Статические объекты класса

Статический объект класса имеет такие же свойства как и обычная статическая переменная, описанная выше, т.е. хранится в .data или .bss сегменте памяти, создается на старте и уничтожается при завершении программы, и инициализируется только один раз. Инициализация объекта происходит, как и обычно — через конструктор класса. Рассмотрим пример со статическим объектом класса.

В строке 3 мы создаем класс Base с конструктором (строка 5) и деструктором (строка 8). При вызове конструктора либо деструктора мы выводим название метода класса в консоль. В строке 14 мы создаем статический объект obj класса Base. Создание этого статического объекта будет происходить только при первом вызове функции foo() в строке 18.

Из-за того, что объект статический, деструктор вызывается не при выходе из функции foo() в строке 15, а только при завершении программы, т.к. статический объект разрушается при завершении программы. Ниже приведен пример той же программы, за исключением того, что наш объект нестатический.

Если мы уберем static при создании переменной в функции foo(), то разрушение объекта будет происходить в строке 15 при каждом вызове функции. В таком случае вывод программы будет вполне ожидаемый для локальной переменной с выделенной памятью на стеке:

Статические члены класса

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

В нашем примере мы создали класс А (строка 3) и класс В (строка 9) со статическими членами класса (строка 15). Мы предполагаем, что при создании объекта b в строке 19 будет создан объект a в строке 15. Так бы и произошло, если бы мы использовали нестатические члены класса. Но вывод программы будет следующим:

Причиной такого поведения является то, что статические члены класса не инициализируются с помощью конструктора, поскольку они не зависят от инициализации объекта. Т.е. в строке 15 мы только объявляем объект, а не определяем его, так как определение должно происходить вне класса с помощью оператора разрешения области видимости (::). Давайте определим члены класса B.

Теперь, после того как мы определили наш статический член класса в строке 18, мы можем увидеть следующий результат программы:

Constructor A
Constructor B
Destructor B
Destructor A

Нужно помнить, что член класса будет один для всех экземпляров класса B, т.е. если мы создали три объекта класса B, то конструктор статического члена класса будет вызван только один раз. Вот пример того, о чем я говорю:

Constructor A
Constructor B1
Constructor B2
Constructor B3
Destructor B3
Destructor B2
Destructor B1
Destructor A

Статические функции

Статические функции пришли в С++ из С. По умолчанию все функции в С глобальные и, если вы захотите создать две функции с одинаковым именем в двух разных .c(.cpp) файлах одного проекта, то получите ошибку о том, что данная функция уже определена (fatal error LNK1169: one or more multiply defined symbols found). Ниже приведен листинг трех файлов одной программы.

Для того чтобы исправить данную проблему, одну из функций мы объявим статической. Например эту:

В этом случае вы говорите компилятору, что доступ к статическим функциям ограничен файлом, в котором они объявлены. И он имеет доступ только к функции sum() из math.cpp файла. Таким образом, используя static для функции, мы можем ограничить область видимости этой функции, и данная функция не будет видна в других файлах, если, конечно, это не заголовочный файл (.h).

Как известно, мы не можем определить функцию в заголовочном файле не сделав ее inline или static, потому что при повторном включении этого заголовочного файла мы получим такую же ошибку, как и при использовании двух функций с одинаковым именем. При определении статической функции в заголовочном файле мы даем возможность каждому файлу (.cpp), который сделает #include нашего заголовочного файла, иметь свое собственное определение этой функции. Это решает проблему, но влечет за собой увеличение размера выполняемого файла, т.к. директива include просто копирует содержимое заголовочного файла в .cpp файл.

Статические функции-члены класса (методы)

Статическую функцию-член вы можете использовать без создания объекта класса. Доступ к статическим функциям осуществляется с использованием имени класса и оператора разрешения области видимости (::). При использовании статической функции-члена есть ограничения, такие как:

  1. Внутри функции обращаться можно только к статическим членам данных, другим статическим функциям-членам и любым другим функциям извне класса.
  2. Статические функции-члены имеют область видимости класса, в котором они находятся.
  3. Вы не имеете доступа к указателю this класса, потому что мы не создаем никакого объекта для вызова этой функции.

Давайте рассмотрим следующий пример:

В классе A в строке 8 у нас есть статическая функция-член foo(). В строке 14, мы вызываем функцию используя имя класса и оператор разрешения области видимости и получаем следующий результат программы:

Из вывода видно, что никакого создания объекта нет и конструктор/деструктор не вызывается.

Если бы метод foo() был бы нестатическим, то компилятор выдал бы ошибку на выражение в строке 14, т.к. нужно создать объект для того, чтобы получить доступ к его нестатическим методам.

Заключение

В одной статье в интернете я нашел совет от автора – «Используйте static везде, где только можно». Я хотел бы написать, почему так делать не стоит, а стоит использовать только в случае необходимости.

  • Статические переменные медленнее, чем нестатические переменные. Для того, чтобы обратиться к статической переменной, нам нужно сделать несколько дополнительных действий, таких как переход в другой сегмент памяти и проверка инициализации переменной. Чаще всего, быстрее выделить локальную переменную на стеке, чем делать дополнительные действия по использованию статической переменной.
  • Если вы используете многопоточность, то здесь вы должны быть крайне осторожными, т.к. возможна ситуация, когда два и более потока захотят писать в одну статическую переменную. Если вы будете использовать нестатические переменные в функциях, то избежите подобного, т.к. для каждого потока будет создана собственная нестатическая переменная.
  • Ключевое слово static является неотъемлемой частью порождающего шаблона проектирования Singleton, который гарантирует, что будет создан только один экземпляр этого класса. В реализации этого паттерна используется и статический объект, и статическая функция-член. На практике вы можете использовать Singleton для создания объекта трейсера, логгера или любого другого объекта, который должен быть один на всё ваше приложение.
  • Иногда для того, чтобы функция отработала только один раз без хранения предыдущего состояния где-то в объекте, используют статические переменные. Пример вы можете посмотреть в разделе «Статические переменные внутри функции». Но это не очень хороший подход, и может привести к долгим часам поиска ошибки, если вы используете многопоточность.
  • На практике, программисты C++ часто используют статические функции-члены как альтернативу обычным функциям, которые не требуют создания объекта для выполнения ее.

Надеюсь, вам понравилась моя статья о ключевом слове static в языке C++. Буду рад любой критике и советам. Всем спасибо!

Источник

It’s interesting to see how small snippets of code can cause so much headache.

Consider this minimal example.

struct c{
    static const int i = 42;
};
int foo(const int& i) { return i; }

int main(){
    return foo(c::i);
}

It won’t compile with gcc or clang, unless compiling with optimization:

> g++ --std=c++11 main.cpp
/usr/bin/ld: /tmp/ccYtUx0X.o: warning: relocation against '_ZN1c1iE' in read-only section '.text'
/usr/bin/ld: /tmp/ccYtUx0X.o: in function 'main':
main.cpp:(.text+0x12): undefined reference to 'c::i'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
> g++ --std=c++11 -O1 main.cpp
# compiles without warnings

The error is cryptic for multiple reasons.

If foo takes its argument by value and not const-ref, then the code also compiles

struct c{
    static const int i = 42;
};
int foo(int i) { return i; }

int main(){
    return foo(c::i);
}

If we use a float instead of an int, we will get the following compiler error with GCC: error: 'constexpr' needed for in-class initialization of static data member 'const float c::i' of non-integral type [-fpermissive]. If we also add constexpr, the code compiles

struct c{
    static constexpr const float i = 42;
};
int foo(const int& i) { return i; }

int main(){
    return foo(c::i);
}

But if I change the signature of int foo(const int&) to int foo(const float&), then the issue is there again

struct c{
    static const constexpr float i = 42;
};
int foo(const float& i) { return i; }

int main(){
    return foo(c::i);
}

So it seems that if there is an implicit conversion between different types, then the code compiles.

The issue also disappears when using a «normal» global variable, ie when using a namespace instead of a struct for scoping symbols. The static keyword, in this case, does not make any difference:

namespace c{
    const int i = 42;
}
int foo(const int& i) { return i; }

int main(){
    return foo(c::i);
}

Is there anything special happening with integral and fundamental types?

Apparently not, the same issue appears when using a user-defined type

struct wrap{int i;};
struct c{
    static constexpr const wrap i{42};
};
void foo(const wrap&) { }

int main(){
    foo(c::i);
}

Then notice that the following snippet compiles without issues

struct c{
    static const int i;
};
const int c::i = 42;
void foo(const int&) { }

int main(){
    foo(c::i);
}

and that it is not possible to rewrite this code with non-integral types, as constexpr requires an initializer where the value is declared.

I mainly analyzed the issue with a C++11 compiler (as it was the scope of the project), but then I decided to see if using a more recent C++ standard would change anything.

Indeed, in C++17, when using constexpr, the issue disappears, thus

struct wrap{int i;};
struct c{
    static constexpr const TYPE i{42};
};
void foo(const TYPE&) { }

int main(){
    foo(c::i);
}

compiles both with #define TYPE int and #define TYPE wrap with g++ --std=c++17 main.cpp.

But without constexpr it does compile only with #define TYPE int (as in C++11) and with optimizations.

Rule of thumb

This is another reason for using the tool designed to fulfill a particular job instead of using paradigms of other languages.

Also, for defining compile-time constants, use constexpr. It helps to avoid errors, see the issue with globals, avoid unnecessary overhead, and in this case, when targeting at least C++17, linker errors too.

But it does not explain why the code behaves differently when using struct, and it also does not offer a solution in those cases we should prefer it over a namespace.

Putting it all together

The issue does not appear if

  • initialization is not inline

  • there is a conversion

  • using constexpr in C++17 (and inline initialization)

  • there is no foo

  • an implicit conversion between the global and parameter required by foo happens

  • foo takes a parameter by value

Also note that for initializing inline, int suffices to be const, but other types (float, user-declared types, …​) need to be declared constexpr.

It seems that static member variables without out-of-class definitions are not real objects contrary to global variables.

I’m unsure where it is exactly stated in the standard and why this difference exists, but GCC and clang act accordingly.

The most explicit reference to this property I could find is the note

Once the static data member has been defined, it exists even if no objects of its class have been created. […​]

This also explains why the code compiles if the constant is an int and foo accepts a float. If a conversion takes place, then «a temporary object is created».

The fact that the code does compile with optimization is probably a side effect. The compiler might inline the function and completely optimize it away, or just replace the call with the literal value after it sees that the address is not taken.

In the case of function taking the parameter by value, the fact that the object does not exist is not an issue, as it is not possible to take the address of the global.

Having said that, following snippets compiles with both GCC and clang, which seems to contradict what I’ve just said

struct c{
	static const int i = 42;
};
int main(){
	&c::i;
}

But if the value is just stored somewhere

struct c{
	static const int i = 42;
};
int main(){
	auto p = &c::i;
}

then it does not compile with undefined reference to 'c::i', even if the value is used as much as before.

But when adding constexpr, why does the code compile since C++17?

inline variables

Since C++17 there are inline variables. Just as with inline functions, the inline keyword is used to avoid ODR-violations.

In this case, the object exists and thus there are no issues.

constexpr variables are, since C++17 inline, so I double-checked and

struct wrap{int i;};
struct c{
	static inline const TYPE i{42};
};
void foo(const TYPE& i) { }
int main(){
	foo(c::i);
}

compiles without constexpr and both with #define TYPE wrap and #define TYPE int.

Why is constexpr not necessary for int?

There is one question open, why don’t we need constexpr for int in the first example?

This is for historic reasons, as constexpr did not exist in the first revisions of the C++ language. Without special-casing int, writing

const int size = 3

void foo(){
	int arr[size]{};
}

would not have been possible.

For the record, in C the code is valid and uses a variable-length array (VLA), an array which stack size is determined at runtime. (making sizeof a runtime operation!).

In C++ the code is equivalent to

void foo(){
	int arr[3]{};
}

just as if size would have been an integral, and not a variable!

In C it is possible to mimic such feature with an enum or macro

enum{ size = 3 };
// or: #define size 3

void foo(){
	int arr[size]{};
}

And note that in both of those cases, there is no object size as it is not possible to get an address from it.

How to fix the linker error

There are multiple solutions, that only depend loosely on each other. Depending on the context some might not be applicable, and for each possible solution, one has to consider the pro and contra.

The best would be to use a never standard, at least C++17, and define the variable as constexpr. If the variable cannot be made constexpr

  • use C++17 and mark the variable constexpr

  • define the variable as inline

  • use a namespace instead of a struct/class

  • if the object is small, change foo to accept it by value

  • create a temporary object when the value is passed to foo. This can be done by creating a local variable, or with an apparently redundant static_cast. In the case of integral types, it can also be done by doing some otherwise unnecessary operations, like adding 0 or use the unary + operator on an integral type.

  • use an enum or define

  • leave the declaration as-is, and add a definition in the corresponding .cpp file. The initialization can be moved to the implementation file, but must be left in the header in case of constexpr.

In C++, we don’t need to specify the static keyword in the declaration of the header and in the definition in the class.

It means that this keyword has to be added only in the header.

You probably know that using the static keyword means that the function is unique in program.
So if you add static in the .h and in the .cpp, you will have like two methods with the same name.
And the compiler won’t appreciate it.

Let’s take two examples, one not working and another yes.

We are going to implement 2 files:

  • MyClass.h
  • MyClass.cpp

The bad

MyClass.h

#ifndef MYCLASS_H_
#define MYCLASS_H_

class MyClass {
public:
    MyClass();
    virtual ~MyClass();

    static void myMethod();
};

#endif /* MYCLASS_H_ */

MyClass.cpp

#include "MyClass.h"

MyClass::MyClass() {
}

MyClass::~MyClass() {
}

static void MyClass::myMethod() {
}

The good

MyClass.h

#ifndef MYCLASS_H_
#define MYCLASS_H_

class MyClass {
public:
    MyClass();
    virtual ~MyClass();

    static void myMethod();
};

#endif /* MYCLASS_H_ */

MyClass.cpp

#include "MyClass.h"

MyClass::MyClass() {
}

MyClass::~MyClass() {
}

void MyClass::myMethod() {
}

Conclusion

A really annoying problem that you’ve just solved.
Great job. cool

I get to help a lot of people learn C# programming every year. As I watch new developers grow and get used to working in C# and Visual Studio, it has become fairly clear to me that reading C# compiler errors and even their documentation is an acquired skill. I’ve made a request for Microsoft to improve the error message feedback in Visual Studio, but until that’s resolved developers still have a tough time working through early obstacles.

Because of this, I’m creating this unusual post to serve as beginner-friendly documentation to what I personally view as the most likely compiler errors a new developer is likely to encounter. Microsoft has wonderful documentation on compiler errors, and this is something that will help you out significantly as you grow, but early on a paragraph or two aimed at a beginner can be exactly what you need.

I also snuck in a few of the more interesting compiler errors I noticed about the maximum limits of the C# compiler, so even if you’re very familiar with C# at this point you’ll likely still learn a few things skimming this list.

Take a look at my list and my recommendations on these issues and let me know if you find this helpful or encounter something I missed.

CS0003 – Out of Memory

This occurs when a computer runs out of memory compiling your code. Close any unnecessary programs and reboot the machine if the problem persists.

CS0004 – Warning Treated as Error

Developers may configure projects to treat certain warnings as errors. These warnings may be specified in the build section of the project’s properties. Typically it is best to resolve the specific warning listed in the build errors since someone wanted that to be treated severely.

CS0015 – Type Name too Long

.NET requires the names of types and namespaces to be less than 1024 characters. If you find yourself getting this error, you may want to reconsider your team’s naming choices.

CS0017 – More than one entry point defined

This occurs when your program has more than one class defined with a static void main method. Remove one of them or manually set the project’s startup object in the project properties.

CS0019 – Operator ‘operator’ cannot be applied to operands of type ‘type’ and ‘type’

This occurs when you try to compare two different types in ways that cannot be compared. For example, checking to see if integer values are equal to Boolean values, subtracting a string from a number, etc. This error often occurs when developers forget what type of data is stored by a particular variable.

CS0020 – Division by Constant Zero

This occurs if you try to force a division by zero in your code. You cannot force a division by zero through a numeric literal or by using a constant for the denominator, but you can declare a variable holding 0 and use that as a denominator.

CS0021 – Cannot apply indexing to type

This occurs when you try to use an array or list-style indexer on a type that doesn’t support it. This often occurs when developers assume they’re working with an array, string, or list and are not.

CS0023 – Operator ‘operator’ cannot be applied to operand of type ‘type’

This occurs when you try to use a mathematical operator with a type that doesn’t support it. For example, trying to generate a negative value of a string. Double check that your variables are of the type you think they are and re-evaluate what you are trying to do.

CS0026 – Keyword this cannot be used in a static method

This error occurs when you are working inside of a static method and try to use the this keyword. Static methods are methods associated with the class itself and not with an instance of the class. As a result, static methods do not have access to any properties, methods, or fields on the class that are not static.

CS0029 – Cannot implicitly convert type ‘type’ to ‘type’

This occurs when you have a variable of one type and are trying to store it into a variable of another type. Some types allow you to automatically convert from one type to another (an implicit conversion), but the types you are using do not support that. You may need to use an explicit cast using (type) syntax.

CS0030 – Cannot convert type ‘type’ to ‘type’

This occurs when there is no implicit or explicit conversion between two different types. If you’re sure you need to do what you’re doing, you could create a method to convert from one type to the other.

CS0031 – Constant value ‘value’ cannot be converted to a ‘type’.

This occurs when you try to store a value into a variable type that cannot store that particular value. For example, if you try to store 5 billion into an integer (which can store values up to around 2.1 billion) you will get this compiler error. You can resolve this error by storing the value into a type that can hold larger values, such as a long.

CS0050 – Inconsistent accessibility: return type ‘type’ is less accessible than method ‘method’

This occurs when a method returns a type that has a visibility or access modifier that is more restrictive than the method and class the method is currently in. For example this error will occur if a public method in a public class returns a type that is defined as internal.

This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.

CS0051 – Inconsistent accessibility: parameter type ‘type’ is less accessible than method ‘method’

This occurs when a method takes in a parameter that is of a type that has a visibility or access modifier that is more restrictive than the method and class the method is currently in. For example this error will occur if a public method in a public class requires a parameter of a type that is defined as internal.

This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.

CS0052 – Inconsistent accessibility: field type ‘type’ is less accessible than field ‘field’

This occurs when a class has a public field that is of a type that has a visibility or access modifier that is more restrictive than the class the method is currently in. For example this error will occur if a class has a public field of a type that is defined as internal.

This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.

CS0053 – Inconsistent accessibility: property type ‘type’ is less accessible than property ‘property’

This occurs when a class has a property of a type that has a visibility or access modifier that is more restrictive than the property’s visibility. For example this error will occur if a public property is of a type that is defined as internal.

This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.

CS0060 – Inconsistent accessibility: base class ‘class1’ is less accessible than class ‘class2’

This occurs when a class inherits from another class but the subclass’s access modifier is less restrictive than the base class’s access modifier. For example this error will occur if a public class inherits from an internal class.

This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.

CS0061 – Inconsistent accessibility: base interface ‘interface 1’ is less accessible than interface ‘interface 2’

This occurs when an interface inherits from another interface but the child interface’s access modifier is less restrictive than the base interface’s access modifier. For example this error will occur if a public interface inherits from an internal interface.

This error usually occurs when developers forget to mark an interface as public. Remember that interfaces have a default access modifier of internal when no access modifier is specified, although every member of an interface is public. Typically the fix for this is to explicitly declare that interface as public.

CS0100 – The parameter name ‘parameter name’ is a duplicate

This occurs when a developer declares a method but uses the same parameter name twice in the method’s parameter list. The fix for this is generally to remove an unneeded parameter or to rename parameters so that all parameters have a different name.

CS0101 – The namespace ‘namespace’ already contains a definition for ‘type’

This occurs when a class is defined twice in the same namespace. This can occur when a class is renamed but the old file still exists, when a developer forgot to mark a class as part of a different namespace, or when a developer intended to use the partial keyword but forgot to specify it. The fix for this will vary based on which files you want and what namespaces they should live in.

CS0102 – The type ‘type name’ already contains a definition for ‘identifier’

This occurs when you declare a member such as a field twice in the same class. Often this is a symptom of using an existing variable name instead of choosing a new name.

CS0103 – The name ‘identifier’ does not exist in the current context

This error often occurs when trying to use a variable defined in another scope. This commonly occurs when you try to define a variable inside of a try block and refer to it in a catch block, when there was no guarantee that the runtime was able to create that variable and therefore the variable is not available.

The fix for this is typically to declare the variable before the try / catch block and update its value from the try block. In this way the catch block will get either the initial value of the variable or its updated value and will be able to reference it.

CS0111 – Type ‘class’ already defines a member called ‘member’ with the same parameter types

This occurs when a developer creates a duplicate method or property with an identical signature consisting of a return type and parameter types. The compiler detects that there will not be a way for code outside of the class to distinguish between one member and the other and so this error is raised. Typically when this occurs you need to either rename one of the two members, change the parameters of one of the methods, or merge the two methods together into one method.

CS0117 – ‘type’ does not contain a definition for ‘identifier’

This occurs when you are trying to call a method or use a property on an instance of an object, but there is no method or property with that name. This can be an issue with capitalization, spelling, or forgetting the name of the member you’re referring to. Code completion can help you find the correct name to use.

CS0120 – An object reference is required for the non-static field, method, or property ‘member’

This often occurs in static methods when you attempt to work with non-static members of the same class. Remember that static methods are associated with the class itself and not with a specific instance of that class. As a result, static methods cannot access properties, fields, and methods that are not marked as static.

The fix for this is often to remove the static keyword from the method that needs to access instance variables. This is counter-intuitive since the compiler pushes you towards adding static in other places, but if you follow that path to its logical conclusion all of your data becomes static eventually, so you’re better off removing the static keyword when confronted by this.

CS0122 – ‘member’ is inaccessible due to its protection level

This occurs when you are trying to call a method or use a property on an instance of an object, but that member is defined as private or protected and you are outside of the class or something that inherits from it. You may not be intended to work with the method or property you are using and you should probably look for public members that might meet your needs without compromising the class’s encapsulation.

CS0127 – Since ‘function’ returns void, a return keyword must not be followed by an object expression

This is a rarer error that occurs when you are in a method defined as void but are trying to return a specific object. Remember that void methods do not return any value so a return statement should just be listed as return;. If you find that you do need to return a value, you should change the return type of the method from void to some specific type.

CS0128 – A local variable named ‘variable’ is already defined in this scope

This occurs when you re-declare a variable that already exists. The solution for this is to either use a different variable name or to remove the type name from your statement and change it from a variable declaration to an assignment statement and re-use the existing variable.

This error often comes from copying and pasting code that declares a new variable.

CS0133 – The expression being assigned to ‘variable’ must be constant

This occurs when you are declaring a const and declaring it to another variable. Constants are evaluated at the time your code is compiled and the compiler will not know the value of your variables. As a result, constants must be set to a literal number or string value.

CS0134 – ‘variable’ is of type ‘type’. A const field of a reference type other than string can only be initialized with null.

This occurs when you are trying to declare a const of a type other than a numeric or string value. Typically, if you have a const that needs to store a reference type you should instead use readonly which is less optimized than a const but works with reference types and ensures that the value will never change.

CS0136 – A local variable named ‘var’ cannot be declared in this scope because it would give a different meaning to ‘var’, which is already used in a ‘parent or current/child’ scope

This occurs when you declare a new variable with the same name as another variable in a visible scope. The solution for this is to either use a different variable name or to remove the type name from your statement and change it from a variable declaration to an assignment statement and re-use the existing variable.

CS0145 – A const field requires a value to be provided

This occurs when you declare a const but do not provide a value. You should set a const equal to some string or numeric variable when declaring it.

CS0150 – A constant value is expected

This occurs when the compiler requires a constant value such as a numeric or string literal but a variable is defined. This can occur when you use a variable in a switch statement or when you are using an array initializer for an array with a variable size.

Switch statements cannot use cases for specific variables, though switch expressions are more flexible.

When working with arrays of varying size, you may want to avoid the use of array initializers and instead manually set the elements of the array after creation.

CS0152 – The label ‘label’ already occurs in this switch statement

This occurs when you duplicate a case statement inside of a switch statement. Typically this occurs when you didn’t notice the case already existed and you can delete your repeated case statement.

CS0160 – A previous catch clause already catches all exceptions of this or of a super type (‘type’)

The ordering of catch statements in a try / catch matters since the runtime will try to match the first catch that applies to the exception it encountered. Because of this, the compiler generates this error if it sees a more specific exception type after a less specific exception type since this results in a case where the more specific catch statement could never be reached.

Move your more specific catch statement above the less specific one to fix this error.

CS0161 – Not all code paths return a value

This occurs because the C# compiler believes that it is possible to get to the end of your method without encountering a return statement. Keep in mind that the C# compiler does very little inferences based on your if statements and even if it may not actually be possible to reach the end of the method without returning, the compiler still thinks it is.

The fix for this is almost always to add a final return statement.

CS0165 – Use of unassigned local variable

This occurs when the compiler sees a variable that is defined but not set to an initial value and determines that the value of that variable needs to be read from later on in the method before the variable is guaranteed to have its value set.

The fix for this is generally to set the variable to be equal to an initial value.

CS0176 – Static member ‘member’ cannot be accessed with an instance reference; qualify it with a type name instead

This occurs when you have a static property or field on a class but are trying to refer to it on a specific instance of that class.

Use the class name instead of the instance variable to access the static member.

CS0201 – Only assignment, call, increment, decrement, and new object expressions can be used as a statement

This typically occurs when you are performing some sort of mathematical operation but not storing the result into a variable. The compiler understands the operation but sees it has no value, so it raises the error.

The fix for this is to store the result of the mathematical operation into a variable or to remove the unnecessary line.

CS0204 – Only 65534 locals are allowed

Apparently you have a method that has over 65 thousand local variables inside of it. The compiler doesn’t like this very much and, frankly, I’m a little concerned why you’d need that many.

Reconsider your life choices.

CS0230 – Type and identifier are both required in a foreach statement

This occurs when you are writing a foreach statement without specifying all parts of the statement.

foreach statements require a variable type, a variable name, the word in, and some variable that can be enumerated over. For example: foreach (string person in people)

CS0234 – The type or namespace name ‘name’ does not exist in the namespace ‘namespace’ (are you missing an assembly reference?)

This occurs when you are trying to refer to a type via its fully-qualified name, including the namespace, but no known type exists with that namespace and type name. This can be a spelling error, a mistake as to which namespace the type lives in, or a correct namespace and type, but your project does not yet have a reference to the project the type is defined in.

If your spelling and namespaces are correct you may need to add a project reference to your project or install a package via nuget.

CS0236 – A field initializer cannot reference the non-static field, method, or property ‘name’.

This occurs when you try to define a field by referencing another field. This error exists to prevent unpredictable behavior based on which field initializers run first.

The fix for this is to set the value of the field in the constructor instead of in a field initializer.

CS0246 – The type or namespace name ‘type/namespace’ could not be found (are you missing a using directive or an assembly reference?)

This occurs when you are trying to refer to a type no known type exists with that type name in the using statements currently in your file.

This is usually a spelling error or a missing using statement at the top of your file.

If your spelling and using statements are correct you may need to add a project reference to your project or install a package via nuget.

CS0266 – Cannot implicitly convert type ‘type1’ to ‘type2’. An explicit conversion exists (are you missing a cast?)

This occurs when you are trying to store a variable of one type into a variable of another type without casting. For example, if you are trying to set a double value into an int variable you will see this error.

The statement “an explicit conversion exists (are you missing a cast)” is telling you that these types are compatible, but the compiler wants to make sure you intend to convert from one to another so it requires you to cast your variable from one type to another.

You cast variables in C# by using parentheses around a type name like this: int num = (int)myDouble;

CS0500 – ‘class member’ cannot declare a body because it is marked abstract

This occurs when you declare an abstract member inside of an abstract class, but you tried to give it a method body (using {}). Abstract members do not have method bodies.

Remove the  {}’s from your abstract method. Alternatively, if you want to provide a default implementation and allow inheriting classes to optionally override yours, use virtual instead of abstract.

CS0501 – ‘member function’ must declare a body because it is not marked abstract, extern, or partial

This occurs when you try to declare a method but forget to give it a method body with {}’s.

This can also occur when you mean to define an abstract method but forgot to use the abstract keyword.

CS0506 – ‘function1’ : cannot override inherited member ‘function2’ because it is not marked “virtual”, “abstract”, or “override”

In C# you have to mark a method as virtual or abstract to be able to override it.

The fix for this is usually to add the virtual keyword to the method in the base class.

CS0507 – ‘function1’ : cannot change access modifiers when overriding ‘access’ inherited member ‘function2’

When overriding a method you must keep the same access modifier as the base method. If the access modifier needs to change, change it in all classes that have the method.

CS0508 – ‘Type 1’: return type must be ‘Type 2’ to match overridden member ‘Member Name’

When overriding a method you cannot change the return type of the method. If you think you need to return something radically different, you may need to introduce a new method instead of overriding an existing one. Alternatively, creative uses of interfaces or inheritance can allow you to return a more specific version of something from a method through polymorphism.

CS0513 – ‘function’ is abstract but it is contained in nonabstract class ‘class’

When you need a method to be abstract, the entire class needs to be abstract as well.

CS0525 – Interfaces cannot contain fields

This one is self-explanatory. An interface is a contract that defines what members need to be present. Fields in classes should be private and are implementation details that do not belong in an interface.

CS0526 – Interfaces cannot contain constructors

This one is self-explanatory. An interface is a contract that defines what members need to be present on an already-constructed class. Interfaces do not care about how an instance is created and cannot denote constructors required for a given class.

CS0531 – ‘member’ : interface members cannot have a definition

This occurs when you try to give an interface member a method body. Interfaces denote capabilities that must be in place, not how those capabilities should work.

If you think you really need a default implementation of a method, you might want to use an abstract class instead of an interface.

CS0534 – ‘function1’ does not implement inherited abstract member ‘function2’

This occurs when you inherit from an abstract class that has abstract members but do not override those members. Because of this, the compiler has no implementation for those abstract members and does not know how to handle them if they are called.

Override the inherited member or mark the inheriting class as abstract as well.

CS0535 – ‘class’ does not implement interface member ‘member’

This occurs when you implement an interface but have not provided members that match those defined in the interface. Members must match the exact type signatures of those defined in the interface and should have names that match those in the interface as well.

CS0645 – Identifier too long

This occurs when you try to name a variable or other identifier something longer than 512 letters long.

What exactly are you trying to do over there that has you naming variables this long?

CS0844 – Cannot use local variable ‘name’ before it is declared.

This occurs when you try to use a variable in a method above when that variable is declared. C# does not have hoisting like some other languages do and variables are only available after they are declared.

Reorder your statements to match your needs.

CS1001 – Identifier expected

This usually occurs when you forget the name of a variable, class, or parameter but have defined other aspects of that line of code. Check some reference materials for what you are trying to do because you’re missing something important.

CS1002 – Semicolon expected

C# requires you to end most statements with a semicolon, including this one. Add a semicolon to the end of the line and all should be well.

CS1026 – ) expected

You have too many opening parentheses and not enough closing parentheses. Check to make sure that all open-parentheses have a matching closing parentheses.

Clicking on a parentheses in Visual Studio will highlight the matching parentheses making it easier to spot the one you’re missing.

CS1033 – Source file has exceeded the limit of 16,707,565 lines representable in the PDB; debug information will be incorrect

What on earth are you even doing over there? Why would you have a source file that requires more than 16 million lines?

Don’t do that. Just no. It’s time to hire a consultant.

CS1034 – Compiler limit exceeded: Line cannot exceed ‘number’ characters

Some people like tabs. Some people like spaces. You, apparently solve this debate by removing line breaks entirely.

You should never need to have a line of code longer than 16 million characters.

CS1035 – End-of-file found, ‘*/’ expected

Your code has a block comment start (/*) but no matching end comment. Add an end comment (*/) and the compiler will be happier.

CS1039 – Unterminated string literal

It looks like you started a string somewhere but forgot to put the other quotation mark. Add it in where it needs to be.

CS1501 – No overload for method ‘method’ takes ‘number’ arguments

This occurs when you are trying to call a method with an incorrect number of arguments or parameters to that method. Check the code or documentation for the method you’re trying to call and ensure you have the correct number of arguments specified.

CS1513 – } expected (missing closing scope)

You have too many opening curly braces and not enough closing curly braces. Check to make sure that all open curly braces have a matching closing curly brace.

Clicking on a { in Visual Studio will highlight the matching } making it easier to spot the one you’re missing.

CS1514 – { expected

Your code requires a { but you didn’t provide one. This often happens after declaring a namespace or class. Check your syntax and add curly braces where they need to go.

CS1525 – Invalid expression term ‘character’

This error seems ambiguous, but most of the time when I see this error it comes from someone trying to use == to assign a value to a variable instead of using the = operator. If this is not your error, you may need to consult some documentation or reference material for valid syntax for what you’re trying to do.

CS1552 – Array type specifier, [], must appear before parameter name

This error occurs when you put [] syntax around the variable name and not around the type name when declaring an array.

Write your arrays as int[] myArray; instead of int myArray[];.

CS1604 – Cannot assign to ‘variable’ because it is read-only

This occurs when you’ve declared a readonly or const variable and are trying to set its value. You can’t do that. If you need to change its value, it can’t be readonly or const.

CS7036 – No argument given that corresponds to the required formal parameter (incorrect method call)

This error occurs when trying to call a base constructor but not specifying a parameter that is required by that constructor.

Double check your base() call and make sure the number and types of parameters lines up with a specific constructor present on your base class.

  • Forum
  • Beginners
  • ISO C++ forbids initialization of member

ISO C++ forbids initialization of member

I can’t find the error and the system always return the errors «ISO C++ forbids initialization of member `username’ «, «making `username’ static «, «invalid in-class initialization of static data member of non-integral type `std::string’ » and the same with psword. Can anybody help me?

Main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>
#include "login.h" 

using namespace std;

int main(){
    
    string us_name;
    string pd;
    
    cout << "Username: ";
    cin >> us_name;
    cout << "Password: ";
    cin >> pd;
    cout << endl << endl;
    
    system("PAUSE");
    return 0;
}

Login.cpp:

1
2
3
4
5
6
7
8
9
10
11
#include "login.h" 
#include <iostream>
#include <string>

using namespace std;

login::login(){
               username = "";
               psword = "";
	
}

login.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef LOGIN_H
#define LOGIN_H

#include <string>

using namespace std;

class login{
            
    public:
           
		login();
        void getUsername();
        void getPassword();    
           
	private:
            
            string username = "Username";
            string psword = "Password";	
		
            
};

#endif 

You can’t initialize the variables username, psword in the login class. Just initialize them in the constructor.

You shouldn’t be assigning values in a header file, unless as the message says, the variable is static. You can use an initialiser list in a constructor though, in the .cpp file:

1
2
3
4
login::login() :  // colon introduces initialiser list
                 username("Username"),
                 psword("Password")
{}

The implementation file (.cpp say) is the place to do ordinary assignment.

Hope all goes well.

you don’t initialize variables inside a class so string username = "Username"; should be string username; and string psword = "Password"; should be string psword;

@joaoareias: Your code should compile in C++11. Maybe your compiler is too old or you have to turn on C++11 features somehow.

Thanks guys

Topic archived. No new replies allowed.

In C#, if we use a static keyword with class members, then there will be a single copy of the type member.

And, all objects of the class share a single copy instead of creating individual copies.


C# Static Variables

If a variable is declared static, we can access the variable using the class name. For example,

using System;

namespace StaticKeyword {

  class Student {

    // static variable
    public static string department = "Computer Science";
  }

  class Program {
    static void Main(string[] argos) {
    
      // access static variable
      Console.WriteLine("Department: " + Student.department);
     
      Console.ReadLine();
    }
  }
}

Output

Department: Computer Science

In the above example, we have created a static variable named department. Since the variable is static, we have used the class name Student to access the variable.


Static Variables Vs Instance Variables

In C#, every object of a class will have its own copy of instance variables. For example,

class Student {

  // instance variable
  public string studentName;
 }

class Program {
  static void Main(string[] args) {

    Student s1 = new Student();
    Student s2 = new Student();
  }
}

Here, both the objects s1 and s2 will have separate copies of the variable studentName. And, they are different from each other.

However, if we declare a variable static, all objects of the class share the same static variable. And, we don’t need to create objects of the class to access the static variables.

Example: C# Static Variable Vs. Instance Variable

using System;
 
namespace StaticKeyword {
 
  class Student {
    static public string schoolName = "Programiz School";
    public string studentName;
 
  }
 
    class Program {
    static void Main(string[] args) {
       
      Student s1 = new Student();
      s1.studentName = "Ram";

      // calls instance variable
      Console.WriteLine("Name: " + s1.studentName);
      // calls static variable
      Console.WriteLine("School: " + Student.schoolName);
 
      Student s2 = new Student();
      s2.studentName = "Shyam";
   
       // calls instance variable
      Console.WriteLine("Name: " + s2.studentName);
      // calls static variable
      Console.WriteLine("School: " + Student.schoolName);
      
      Console.ReadLine();
    }
  }
}

Output

Name: Ram
School: Programiz School
Name: Shyam
School: Programiz School

In the above program, the Student class has a non-static variable named studentName and a static variable named schoolName.

Inside the Program class,

  • s1.studentName / s2.studentName — calls the non-static variable using objects s1 and s2 respectively
  • Student.schoolName — calls the static variable by using the class name

Since the schoolName is the same for all students, it is good to make the schoolName static. It saves memory and makes the program more efficient.


C# Static Methods

Just like static variables, we can call the static methods using the class name.

class Test {

  public static void display() {....}

}

class Program {
  static void Main(string[] args) {

    Test.display();
  }
}

Here, we have accessed the static method directly from Program classes using the class name.

When we declare a method static, all objects of the class share the same static method.

Example: C# Static and Non-static Methods

using System;
 
namespace StaticKeyword {
 
  class Test {
 
    public void display1() {
 
      Console.WriteLine("Non static method");
    }
    public static void display2() {
 
      Console.WriteLine("Static method");
    }
  }
 
  class Program {
    static void Main(string[] args) {
 
      Test t1 = new Test();
      t1.display1();
      Test.display2();    
      Console.ReadLine();
    }
  }
}

Output

Non static method
Static method

In the above program, we have declared a non-static method named display1() and a static method named display2() inside the class Test.

Inside the Program class,

  • t1.display1() — access the non-static method using s1 object
  • Test.display2() — access the static method using the class name Test

Note: In C#, the Main method is static. So, we can call it without creating the object.


C# Static Class

In C#, when we declare a class as static, we cannot create objects of the class. For example,

using System;

namespace StaticKeyword {

  static class Test {
    static int a = 5;
    static void display() {

      Console.WriteLine("Static method");
    }
  
    static void Main(string[] args) {

      // creating object of Test
      Test t1 = new Test();
      Console.WriteLine(a);
      display();
    }
  }
}

In the above example, we have a static class Test. We have created an object t1 of the class Test.

Since we cannot make an object of the static class, we get the following error:

error CS0723: Cannot declare a variable of static type 'Test' 
error CS0712: Cannot create an instance of the static class

Notice the field and method of the static class are also static because we can only have static members inside the static class.

Note: We cannot inherit a static class in C#. For example,

static class A {
  ...
}

// Error Code
class B : A {
  ...
}

Access static Members within the Class

If we are accessing the static variables and methods inside the same class, we can directly access them without using the class name. For example,

using System;
 
namespace StaticKeyword {
 
  class Test {
 
    static int age = 25;
    public static void display() {
 
      Console.WriteLine("Static method");
    }
   
    static void Main(string[] args) {
 
      Console.WriteLine(age);
      display();
      Console.ReadLine();
    }
  }
}

Output

25
Static method

Here, we are accessing the static field age and static method display() without using the class name.


Updated on: June 28, 2020


In C#, static means something which cannot be instantiated. You cannot create an object of a static class and cannot access static members using an object.

C# classes, variables, methods, properties, operators, events, and constructors can be defined as static using the static modifier keyword.

Static Class

Apply the static modifier before the class name and after the access modifier to make a class static.
The following defines a static class with static fields and methods.

public static class Calculator
{
    private static int _resultStorage = 0;
    
    public static string Type = "Arithmetic";

    public static int Sum(int num1, int num2)
    {
        return num1 + num2;
    }

    public static void Store(int result)
    {
        _resultStorage = result;
    }
}

Above, the Calculator class is a static. All the members of it are also static.

You cannot create an object of the static class; therefore the members of the static class can be accessed directly using a class name like ClassName.MemberName, as shown below.

class Program
{
    static void Main(string[] args)
    {
        var result = Calculator.Sum(10, 25); // calling static method
        Calculator.Store(result); 

        var calcType = Calculator.Type; // accessing static variable
        Calculator.Type = "Scientific"; // assign value to static variable
    }
}

Rules for Static Class

  1. Static classes cannot be instantiated.
  2. All the members of a static class must be static; otherwise the compiler will give an error.
  3. A static class can contain static variables, static methods, static properties, static operators, static events, and static constructors.
  4. A static class cannot contain instance members and constructors.
  5. Indexers and destructors cannot be static
  6. var cannot be used to define static members. You must specify a type of member explicitly after the static keyword.
  7. Static classes are sealed class and therefore, cannot be inherited.
  8. A static class cannot inherit from other classes.
  9. Static class members can be accessed using ClassName.MemberName.
  10. A static class remains in memory for the lifetime of the application domain in which your program resides.

Static Members in Non-static Class

The normal class (non-static class) can contain one or more static methods, fields, properties, events and other non-static members.

It is more practical to define a non-static class with some static members, than to declare an entire class as static.

Static Fields

Static fields in a non-static class can be defined using the static keyword.

Static fields of a non-static class is shared across all the instances. So, changes done by one instance would reflect in others.

public class StopWatch
{
    public static int NoOfInstances = 0;
    
    // instance constructor
    public StopWatch()
    {
        StopWatch.NoOfInstances++;
    }
}

class Program
{
    static void Main(string[] args)
    {
        StopWatch sw1 = new StopWatch();
        StopWatch sw2 = new StopWatch();
        Console.WriteLine(StopWatch.NoOfInstances); //2 
			
        StopWatch sw3 = new StopWatch();
        StopWatch sw4 = new StopWatch();
        Console.WriteLine(StopWatch.NoOfInstances);//4
    }
}

Static Methods

You can define one or more static methods in a non-static class. Static methods can be called without creating an object. You cannot call static methods using an object of the non-static class.

The static methods can only call other static methods and access static members. You cannot access non-static members of the class in the static methods.

class Program
{
    static int counter = 0;
    string name = "Demo Program";

    static void Main(string[] args)
    {
        counter++; // can access static fields
        Display("Hello World!"); // can call static methods

        name = "New Demo Program"; //Error: cannot access non-static members
        SetRootFolder("C:MyProgram"); //Error: cannot call non-static method
    }

    static void Display(string text)
    {
        Console.WriteLine(text);
    }

    public void SetRootFolder(string path) {  }
}

Rules for Static Methods

  1. Static methods can be defined using the static keyword before a return type and after an access modifier.
  2. Static methods can be overloaded but cannot be overridden.
  3. Static methods can contain local static variables.
  4. Static methods cannot access or call non-static variables unless they are explicitly passed as parameters.

Static Constructors

A non-static class can contain a parameterless static constructor. It can be defined with the static keyword and without access modifiers like public, private, and protected.

The following example demonstrates the difference between static constructor and instance constructor.

public class StopWatch
{
    // static constructor
    static StopWatch()
    {
        Console.WriteLine("Static constructor called");
    }

    // instance constructor
    public StopWatch()
    {
        Console.WriteLine("Instance constructor called");
    }

    // static method
    public static void DisplayInfo()
    {
        Console.WriteLine("DisplayInfo called");
    }

    // instance method
    public void Start() { }

    // instance method
    public void Stop() {  }
}

Above, the non-static class StopWatch contains a static constructor and also a non-static constructor.

The static constructor is called only once whenever the static method is used or creating an instance for the first time.
The following example shows that the static constructor gets called when the static method called for the first time.
Calling the static method second time onwards won’t call a static constructor.

StopWatch.DisplayInfo(); // static constructor called here
StopWatch.DisplayInfo(); // none of the constructors called here

Output:


Static constructor called.
DisplayInfo called
DisplayInfo called

The following example shows that the static constructor gets called when you create an instance for the first time.

StopWatch sw1 = new StopWatch(); // First static constructor and then instance constructor called 
StopWatch sw2 = new StopWatch();// only instance constructor called 
StopWatch.DisplayInfo();

Output:


Static constructor called
instance constructor called
instance constructor called
DisplayInfo called

Rules for Static Constructors

  1. The static constructor is defined using the static keyword and without using access modifiers public, private, or protected.
  2. A non-static class can contain one parameterless static constructor. Parameterized static constructors are not allowed.
  3. Static constructor will be executed only once in the lifetime. So, you cannot determine when it will get called in an application if a class is being used at multiple places.
  4. A static constructor can only access static members. It cannot contain or access instance members.

Learn more about Static class and static constructor.

Static members are stored in a special area in the memory called High-Frequency Heap.
Static members of non-static classes are shared across all the instances of the class.
So, the changes done by one instance will be reflected in all the other instances.

Понравилась статья? Поделить с друзьями:
  • Error makefile 71 command syntax error
  • Error make sure you have a working qt qmake on your path
  • Error major abi change detected please run upgrade instead
  • Error main must return int как исправить
  • Error main method not found in class main please define the main method as