Приветствую Вас ГостьЧетверг, 10.07.2025, 10:31

Light Midnight Inc.


Каталог статей

Главная » Статьи » Программирование » С/С++/MFC

Основы C++ (part 1)

Препроцессор в C++

NB: Конструкция #define func(args) ... не определяет функцию (как многие полагают), а только правило макроподстановки. То есть код:

#define sqr(x) x*x
int y = 5;
int z = sqr(y+1);

не будет вычислять квадрат шести и класть его в z, вместо этого после отработки препроцессора последняя строчка превратится в:

int z = y+1*y+1;

Это всё что сделает макрос sqr. Т.е. в z окажется 11, а никак не 36.

Следует также отметить, что директива #include ... не делает ничего магического - всего лишь вставляет вместо себя текст указанного файла. Т.е. включать можно файлы любого типа, главное - чтобы результат их включения удовлетворял правилам языка.

Ключевое слово static

NB: В С/С++ имеется порядка пяти-шести (в зависимости от версии стандарта) применений ключевого слова static:

  1. Глобальная переменная, объявленная с ключевым словом static, будет иметь internal linkage. Таким образом использование static помогает избавиться от ошибок линковки из-за того что в разных объектах трансляции были объявлены глобальные переменные с одинаковыми именами. (Замечу что наличие глобальных переменных скорее всего свидетельствует об ошибках проектирования. В крайнем случае следует использовать синглтоны.)
  2. Глобальная функция, объявленная с ключевым словом static, будет также иметь internal linkage. Собственно - см. выше. Наличие глобальных функций об ошибках проектирования не свидетельствует... как правило.
  3. Локальная переменная, объявленная с ключевым словом static, будет иметь локальную область видимости и время жизни - от инициализации до завершения программы. Инициализация локальной статической переменной будет происходить в тот момент когда выполнение программы пройдёт через строчку с объявлением переменной. Если конструктор локальной статической переменной выбросит исключение (которое будет обработано), то при следующем прохождении этой строчки будет также выполнена попытка инициализации переменной. Если инициализация статической локальной переменной прошла успешно, инициализации более происходить не будет. По-умолчанию, статические переменные POD-типов инициализируются нулями.
  4. Переменная-член класса, объявленная с ключевым словом static, будет иметь глобальную область видимости (через класс, разумеется) и время жизни - от инициализации до завершения программы. Инициализация статических переменных-членов происходит так же как и глобальных переменных: в глобальной области видимости объявляется тип переменной, затем её имя (с указанием класса в котором она содержится), и, опционально, инициализатором: int MyClass::variable_ = 5; По-умолчанию, статические переменные-члены также будут инициализированы нулями.
  5. Функция-член класса, объявленная с ключевым словом static, будет иметь глобальную область видимости. В отличие от других функций-членов, статический метод не будет получать указатель на текущий объект и соотвественно не может быть объявлен со спецификаторами const или virtual, по этой же причине статические методы не имеют прямого доступа к нестатическим полям класса.
  6. ISO/IEC 9899:TC2
    6.7.5.3 Function declarators (including prototypes)
    7    ... If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

    Т.е. (как я это понял) ключевое слово static в объявлении функции, внутри указания размера массива, обозначает что размер массива может быть любой, но не менее чем из указанного после слова static количества элементов. Разобраться с данным применением у меня пока не было возможности, буду благодарен если кто-то выложит пример в котором покажет отличия вызываемые наличием этого ключевого слова. Гцц похоже его игнорирует, а Visual C++ стандарт C99 вообще не признаёт.

Список инициализации в C++

NB: Единственный способ инициализировать константные поля, поля-ссылки и вызвать конструкторы родительских классов с определёнными параметрами - список инициализации. Список инициализации отделяется от прототипа конструктора двоеточием и состоит из инициализаторов разделённых запятыми. Например он может выглядеть так:

struct A
{
 A(int){}
};

struct B : A
{
 const int c_;
 unsigned d_;
 unsigned& r_;
 B() : A(5), c_(4), r_(d_)
 {
 d_ = 5;
 }
};

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

Ключевое слово const

Просто факты... о которых не все знают:

  1. Ключевое слово const перед объявлением массива или указателя относится к элементам массива, а не самой переменной-массиву. Т.е. const int* p; указывает на элемент типа const int и его значение нельзя изменять. При этом ничто не запрещает изменять значение самого указателя, если хотите это запретить - напишите const после "звёздочки".
  2. Любой тип T приводим к типу const T, массивы из элементов таких типов также приводимы, так что не стоит волноваться из-за того что у вас указатель на строку типа char*, а функция принимает в себя аргумент типа const char*. Вообще слова const и static в объявлениях функций следует расставлять строго до тех пор пока программа не прекратит компилироваться. Я ещё ни разу не видел чтобы компилирующаяся программа переставала правильно работать от расстановки const и static (на нормальных компиляторах). Винт закручивается следующим образом: до срыва, затем пол-оборота назад.
  3. Ключевое слово const перед структурой или классом, по сути, добавляет ключевое слово const ко всем его полям. Исключение составляют поля-ссылки, поля объявленные с ключевым словом mutable и статические поля. Т.е., для примера выше, следующий код будет успешно скомпилирован (и, по идее, изменит значение поля d_):
    const B b;
    b.r_=7;
  4. Константные методы отличаются от неконстантных лишь тем что указатель this имеет тип не T* const, а const T* const со всеми вытекающими отсюда последствиями. Неконстантные методы не могут быть вызваны у объектов являющимися константными.

К чему эпиграф собственно? В конце марта - начале апреля, мне пришлось принять немало собеседований по Си и С++ и я был несколько удивлён тому уровню знаний, что есть у людей, и теми деньгами, которые они за эти знания хотят получать (возможно что это проблема лишь моего района замкадья). Если у вас нет знания английского - средняя зарплата по городу - ваш потолок навек (и то в лучшем случае). Если вы понимаете, что ваше знание языка программирования не идеально, но при этом пишете его в резюме - будьте добры, перечитайте книжку по конструкциям языка, можно не затрагивая стандартную библиотеку. Пара недель чтения по вечерам стоят дополнительных $300 - $500 в месяц. Ученье - свет... и право вставать на работу уже после того как рассветёт.

Категория: С/С++/MFC | Добавил: Cromartie (31.01.2013)
Просмотров: 424 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Наш опрос
Оцените мой сайт
Всего ответов: 543
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Реклама
Cheсking
Часы
Мини-чат
200
Друзья Сайта
  • Light Midnight - Ваша Еда
  • Light Midnight - Anim as life style
  • Поиск