notes

Static, Inline, Friend

Table of Content

Inline

  1. Советует компилятору встроить данную функцию
  2. В месте вызова inline функции должно быть известно её определение
  3. inlineфункции можно определять в заголовочных файлах
  4. Все методы, определённые внутри класса, являются inline.
  5. При линковке из всех версий inline-функции выбирается только одна.
  6. Все определения одной и той же inline функции должны быть идентичны
  7. inline - это совет компилятору, а не указ

Правило одого определения

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

Friend

  1. Дружественный класс имеет доступ к приватным полям своего друга.
  2. Дружественная функция имеет доступ к приватным полям класса. Эту функцию нужно определить внутри класса с ключевым словом friend (удобно для переопределения операторов)
     struct String {
         ...
         friend std::ostream & operator << (std::ostream & os, String const & s) {
             return os << s.data_;
         }
     private:
         size_t size_;
         char * data_;
     };
    
  3. Для одного класса можно определить дружественным метод другого класса.
     struct String;
     struct StringBuffer {
         void append (string const & s);
         void append (char const * s) { ... };
     };
    
     struct String {
         friend void StringBuffer::append(String const & s);
     };
    
     void StringBuffer::append(String const & s) {
         append(s.data_);
     }
    
  4. Отношение дружбы
    • Отношение дружбы не симметрично (из A друг Б не следует что Б друг А)
    • Отношение дружбы н етранзитивно (из А друг Б и Б друг С не следует что А друг С)
    • Отношение дружбы сильнее, чем отношение наследования
  5. Вывод: стоит избегать ключевого слова friend, так как оно нарушеает инкапсуляцию.

Глобальные переменные

  1. Объявление глобальных переменных

     extern int global;
    
  2. Определение глобальное переменной

     global = 10;
    
  3. При отсутствии определения, инициализируются 0 (в отличии от локальных переменных).

  4. Время жизни:
    • Инициализируются при запуске программы
    • Заканчивается при выходе из программы
  5. Хранится в специальном разделе памяти для хранения глобальных переменных.

  6. Недостатки
    • Мастабируемость. К примеру есть объект использующий глобальную переменную, тогда нам нужно будет контролировать их взаимодейтвие друг с другом. Усложнится многопоточная разработка.
    • Побочные эффекты - т.е. поведение функции зависит не только от её аргументов.
    • Порядок инициализации - порядок инициализации не определён, и как следствие может возникнуть неопределенность в определении этих переменных.

Статические глобальные переменные

  1. Статическая глобальне переменная - это глобальная переменная, доступная только в пределах модуля.
  2. Определение
     static int global = 10;
    
     void f () {
         ++global;
     }
    
  3. В соседнем модуле можно определить статическую глобальную переменную с таким же именем.
  4. Проблемы:
    • Масштабируемость (многопоточность)
    • Побочные эффекты

Статическая локальная переменная

  1. Статическая локальная переменная - это глобальная переменная, доступная только в пределах функции.

  2. Время жизни такой переменной - от первого вызова функции до конца программы.

  3. Пример:
     int next(int start = 0) {
         static int k = start;
         return k++;
     }
    
     next(10); // 10
     next(20); // 11
    
  4. Проблемы:
    • Мастабируемость
    • Побочные эффекты

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

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

Статические поля класса

  1. Статические поля класса - это глобальные переменные, определённые внутри класса.

     struct User {
         User() {
             ++instances_;
         }
    
         ~User() {
             --instances_;
         }
     private:
         static size_t instances_;
     }
    
     size_t User::instances_ = 0;
    
  2. Определить такую переменную нужно снаружи класса.
  3. Для доступа к статическим полям не нужен объект.

Статические методы

  1. Статические методы - функции определённые внутри класса и имеющие доступ к закрытым полям и методам.

     struct User {
         ...
         static size_t count() { return instances_; }
         static void transform(User user) {
             // we are able to access private fields
         }
     private:
         static size_t instances_;
     }
    

Singlteon

struct Singleton {
    static Singleton & instance() {
        static Singleton s;
        return s;
    }
private:
    Singleton () {}
    Singleton(Singleton const &);
    Singleton & operator=(Singleton const &);
};

Singleton & s = Singleton::instance();