C++ собеседования
839 subscribers
106 photos
222 links
Подготовка к собеседованиям на позицию C/C++ разработчик

Еще больше на сайте https://frontview-it.ru

Backend собеседования - @frontview_backend
C/C++ работа - @frontview_cpp_vacancies
Все IT вакансии - @frontview_all_vacancies
Download Telegram
🔥 Что такое конструкторы и деструкторы?

Конструкторы и деструкторы — специальные функции-члены класса в C++, управляющие жизненным циклом объектов.

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

Деструктор вызывается при удалении объекта и используется для освобождения ресурсов. Имя деструктора совпадает с именем класса, но с префиксом тильда ~, и также не имеет возвращаемого значения.

Пример:


class MyClass {
public:
MyClass() {
// Конструктор: выделяем память или инициализируем данные
data = new int[10];
}

~MyClass() {
// Деструктор: освобождаем выделенную память
delete[] data;
}

private:
int* data;
};


В этом примере конструктор MyClass() выделяет память для массива, а деструктор ~MyClass() освобождает эту память. Это обеспечивает корректное управление ресурсами и предотвращает утечки памяти.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42
🔥 Что такое специализация шаблонов?

Специализация шаблонов в C++ позволяет определять особое поведение шаблонной функции или класса для конкретных типов данных. Это полезно, когда общая реализация шаблона не подходит для определенного типа, и требуется отдельная реализация.

Полная специализация — это определение шаблона для конкретного набора типов параметров. Например:


// Общий шаблон функции
template <typename T>
void print(const T& value) {
std::cout << value << std::endl;
}

// Полная специализация для типа int
template <>
void print<int>(const int& value) {
std::cout << "Integer: " << value << std::endl;
}


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


// Общий шаблон класса
template <typename T, typename U>
class MyClass { /*...*/ };

// Частичная специализация для случая, когда U — это int
template <typename T>
class MyClass<T, int> { /*...*/ };


В этом примере создается особая версия MyClass для всех типов T, когда U равно int.

Специализация шаблонов обеспечивает гибкость и оптимизацию кода, позволяя адаптировать шаблоны под специфические требования различных типов данных.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🔥 Что такое RAII?

RAII (Resource Acquisition Is Initialization) — идиома в C++, которая связывает время жизни ресурсов с временем жизни объектов. При использовании RAII ресурсы выделяются в конструкторе и освобождаются в деструкторе.

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

Пример использования RAII для управления файловым дескриптором:


#include <fstream>

class FileWrapper {
public:
FileWrapper(const std::string& filename) {
file.open(filename);
// Проверяем, успешно ли открыт файл
if (!file.is_open()) {
throw std::runtime_error("Failed to open file");
}
}

~FileWrapper() {
// Деструктор: закрываем файл
file.close();
}

std::fstream& get() {
return file;
}

private:
std::fstream file;
};

// Использование класса
void processFile(const std::string& filename) {
FileWrapper fw(filename);
std::fstream& file = fw.get();
// Работа с файлом
}


В этом примере конструктор FileWrapper открывает файл, а деструктор автоматически закрывает его при выходе из области видимости объекта fw. Это гарантирует корректное управление ресурсами без явного вызова close().

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
🔥 Что такое умные указатели ?

Умные указатели (smart pointers) в C++ — это объекты, облегчающие управление динамической памятью. Они автоматически освобождают память, предотвращая утечки и обеспечивая безопасность.

Стандартная библиотека предлагает несколько типов умных указателей:

1. std::unique_ptr — обладает уникальным владением объектом. Объект удаляется при уничтожении указателя. Копирование запрещено, но возможна передача владения через перемещение.


#include <memory>

void func() {
std::unique_ptr<int> ptr(new int(5));
// Работа с ptr
} // Память автоматически освобождается здесь


2. std::shared_ptr — разделяет владение объектом между несколькими указателями. Ведется подсчет ссылок, и объект удаляется, когда последний указатель уничтожается.


#include <memory>

void func() {
std::shared_ptr<int> ptr1(new int(10));
{
std::shared_ptr<int> ptr2 = ptr1;
// Счетчик ссылок увеличился до 2
} // ptr2 выходит из области видимости, счетчик уменьшается до 1
} // Счетчик достигает 0, память освобождается


3. std::weak_ptr — слабая ссылка на объект, управляемый std::shared_ptr. Не увеличивает счетчик ссылок и используется для предотвращения циклических зависимостей.


#include <memory>

struct Node {
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // Используем weak_ptr
};


Умные указатели помогают писать безопасный и эффективный код, автоматизируя управление ресурсами и следуя идиоме RAII.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
🔥 Как создавать пользовательские классы исключений?

Пользовательские классы исключений в C++ позволяют создавать специальные типы ошибок, которые можно точно обрабатывать при возникновении исключений.

Чтобы создать собственный класс исключения, наследуйте его от стандартного класса исключений, например, от std::exception или любого его потомка.

Пример создания пользовательского исключения:


#include <exception>
#include <string>

class MyException : public std::exception {
public:
explicit MyException(const std::string& message)
: msg_(message) {}

virtual const char* what() const noexcept override {
return msg_.c_str(); // Возвращаем сообщение об ошибке
}

private:
std::string msg_; // Храним сообщение об ошибке
};


Использование пользовательского исключения:


void riskyFunction() {
// Некоторый код, который может вызвать ошибку
throw MyException("An error occurred"); // Бросаем наше исключение
}

int main() {
try {
riskyFunction();
} catch (const MyException& e) {
std::cout << "Caught MyException: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cout << "Caught std::exception: " << e.what() << std::endl;
}
return 0;
}


В этом примере класс MyException наследует от std::exception и переопределяет метод what(), чтобы вернуть пользовательское сообщение об ошибке. При вызове throw MyException("An error occurred") исключение может быть перехвачено и обработано специфическим образом в блоке catch.

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

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍61
🔥 Как реализовать паттерн Factory Method?

Паттерн «Factory Method» позволяет создавать объекты через общий интерфейс, не указывая их конкретные классы. Суперкласс объявляет фабричный метод, а подклассы реализуют его, создавая нужные объекты.

Пример реализации:


// Абстрактный продукт
class Product {
public:
virtual void use() = 0;
virtual ~Product() = default;
};

// Конкретный продукт
class ConcreteProduct : public Product {
public:
void use() override {
// Реализация метода use для ConcreteProduct
}
};

// Абстрактный создатель
class Creator {
public:
virtual Product* factoryMethod() = 0;
void someOperation() {
Product* product = factoryMethod();
product->use();
delete product; // Освобождаем память
}
virtual ~Creator() = default;
};

// Конкретный создатель
class ConcreteCreator : public Creator {
public:
Product* factoryMethod() override {
return new ConcreteProduct();
}
};


В этом примере Creator определяет фабричный метод factoryMethod(), который создает объекты типа Product. Класс ConcreteCreator переопределяет этот метод, создавая и возвращая экземпляр ConcreteProduct. Клиентский код вызывает someOperation(), не зная о конкретных классах продуктов. Это обеспечивает гибкость и упрощает добавление новых типов продуктов и создателей без изменения существующего кода.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
🔥 Объясни процесс компиляции в C++

Процесс компиляции в C++ состоит из нескольких этапов:

1. Предварительная обработка (Preprocessing): Обрабатываются директивы препроцессора, такие как #include и #define. Например:


#include <iostream> // Включение заголовочного файла iostream
#define MAX 100 // Определение константы MAX


2. Компиляция: Преобразование кода C++ в ассемблерный код.

3. Ассемблирование (Assembly): Перевод ассемблерного кода в объектный код (машинные инструкции).

4. Линковка (Linking): Объединение объектных файлов и библиотек в исполняемый файл.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
🔥 Как работает наследование в C++?

Наследование в C++ позволяет создавать новые классы на основе существующих, используя их свойства и методы. Это способствует повторному использованию кода и иерархической организации.

Пример наследования:


class Animal {
public:
void eat() {
// Общий метод для всех животных
}
};

class Dog : public Animal {
public:
void bark() {
// Метод, специфичный для собак
}
};


В этом примере класс Dog наследует публичные члены класса Animal. Это означает, что объекты Dog могут использовать методы eat() и bark().

Типы наследования:

- Публичное наследование (public): публичные члены базы остаются публичными в производном классе.
- Защищённое наследование (protected): публичные и защищённые члены базы становятся защищёнными.
- Приватное наследование (private): все члены базы становятся приватными.

Наследование позволяет реализовать полиморфизм и использовать виртуальные функции для переопределения методов в производных классах.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤔1
🔥 Как реализовать шаблоны с переменным числом параметров?

Для реализации шаблонов с переменным числом параметров в C++ используются вариативные шаблоны (variadic templates). Они позволяют создавать функции и классы, работающие с произвольным числом аргументов.

Пример функции для вывода значений:


#include <iostream>

void print() {
// Базовый случай: нет аргументов
}

template<typename T, typename... Args>
void print(T first, Args... args) {
std::cout << first << " ";
print(args...); // Рекурсивный вызов с оставшимися аргументами
}


Использование:


print(1, 2.5, "текст");
// Вывод: 1 2.5 текст


В этом примере функция print принимает первый аргумент first и пакет параметров Args.... Она выводит first и рекурсивно вызывает себя с оставшимися аргументами args....

С появлением C++17 можно использовать fold expressions для упрощения кода:


template<typename... Args>
void print(Args... args) {
(std::cout << ... << args) << std::endl; // Вывод всех аргументов
}


Это позволяет избежать рекурсии и сделать код более компактным.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🔥 Объясни разницу между public, protected и private

В C++ есть три уровня доступа для членов класса: public, protected и private.

- public: члены класса, помеченные как public, доступны из любого места в программе. Их можно вызвать или изменить из любого контекста.

- protected: члены, помеченные как protected, доступны внутри самого класса, а также в его потомках (классах-наследниках). Однако они недоступны вне этих классов.

- private: приватные члены доступны только внутри самого класса. Ни внешние функции, ни потомки не имеют к ним доступа.

Пример:


class Base {
public:
int publicMember; // Доступен всем

protected:
int protectedMember; // Доступен классу и наследникам

private:
int privateMember; // Доступен только внутри класса Base
};

class Derived : public Base {
public:
void accessMembers() {
publicMember = 1; // OK
protectedMember = 2; // OK
// privateMember = 3; // Ошибка: privateMember недоступен
}
};

void externalFunction() {
Base obj;
obj.publicMember = 1; // OK
// obj.protectedMember = 2; // Ошибка: protectedMember недоступен
// obj.privateMember = 3; // Ошибка: privateMember недоступен
}


Таким образом, выбор уровня доступа определяет, какие части кода могут использовать данные или функции класса.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Подписывайся на наши новые каналы!

👩‍💻 Git
🖥 SQL
👩‍💻 QA
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥 Какие существуют основные методы оптимизации C++ программ?

1. Выбор эффективных алгоритмов и структур данных. Оптимальный алгоритм может значительно снизить время выполнения и потребление памяти.

2. Включение оптимизаций компилятора. Использование флагов компиляции, таких как -O2 или -O3, позволяет генерировать более эффективный машинный код.

3. Избегание избыточного копирования. Передача объектов по const ссылке или использование std::move для перемещения ресурсов.


void processData(const std::vector<int>& data); // Передача по константной ссылке

std::vector<int> data = getData();
processData(std::move(data)); // Перемещение данных


4. Использование эффективных контейнеров. Выбор подходящих контейнеров STL, таких как std::vector вместо std::list для последовательного доступа.

5. Уменьшение количества динамических выделений памяти. Предпочтение статического или стекового размещения объектов, использование пулов памяти.

6. Инлайн-функции. Использование ключевого слова inline для небольших часто вызываемых функций.

7. Профилирование кода. Применение инструментов для выявления узких мест и точечной оптимизации.

8. Параллелизация. Использование многопоточности (std::thread) или SIMD-инструкций для распараллеливания вычислений.

9. Избежание виртуальных функций там, где это возможно. Виртуальные вызовы могут быть медленнее из-за динамической диспетчеризации.

10. Оптимизация работы с вводом-выводом. Буферизация операций ввода-вывода и минимизация обращений к диску.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
🔥 Как работает Make и как написать makefile?

Make — это утилита для автоматизации сборки проектов из исходного кода. Она использует Makefile — специальный файл, в котором описаны правила сборки и зависимости между файлами.

Основная идея Make: при сборке пересобираются только те части проекта, которые были изменены, что ускоряет процесс.

Простой пример Makefile для программы на C++:


# Компилятор и флаги компиляции
CXX = g++
CXXFLAGS = -Wall -std=c++17

# Исполняемый файл
TARGET = program

# Список объектов
OBJS = main.o utils.o

# Цель по умолчанию
all: $(TARGET)

# Правило сборки исполняемого файла
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS)

# Правило для компиляции main.cpp
main.o: main.cpp utils.h
$(CXX) $(CXXFLAGS) -c main.cpp

# Правило для компиляции utils.cpp
utils.o: utils.cpp utils.h
$(CXX) $(CXXFLAGS) -c utils.cpp

# Очистка сгенерированных файлов
clean:
rm -f $(OBJS) $(TARGET)


В этом Makefile определены:

- Переменные: CXX, CXXFLAGS, TARGET, OBJS.
- Цели (targets): all, $(TARGET), main.o, utils.o, clean.
- Зависимости: например, main.o зависит от main.cpp и utils.h.
- Команды: команды компиляции и сборки.

Чтобы использовать Makefile:

- Запуск сборки: make или make all.
- Очистка файлов: make clean.

Make автоматически отслеживает временные метки файлов и пересобирает только те части, которые изменились, вместе с зависимостями.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🔥 Объясни разницу между std::lock_guard и std::unique_lock

std::lock_guard и std::unique_lock — оба являются инструментами для управления мьютексами в многопоточном программировании, обеспечивая автоматическую блокировку и разблокировку.

std::lock_guard — простой RAII-объект, который блокирует мьютекс при создании и автоматически разблокирует его при уничтожении. Он не предоставляет возможности контроля над блокировкой после создания.


std::mutex mtx;

void func() {
std::lock_guard<std::mutex> lock(mtx);
// Критическая секция
} // Мьютекс разблокируется автоматически здесь


std::unique_lock — более гибкий RAII-объект, который позволяет управлять блокировкой мьютекса. С его помощью можно:

- Откладывать блокировку (defer locking)
- Разблокировать мьютекс до конца области видимости
- Перемещать объект unique_lock между функциями


std::mutex mtx;

void func() {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // Блокировка отложена
// ... некоторые операции
lock.lock(); // Ручная блокировка
// Критическая секция
lock.unlock(); // Ручная разблокировка
// ...
} // Если мьютекс заблокирован, он разблокируется автоматически


Основные отличия:

- Контроль блокировки: std::unique_lock позволяет откладывать блокировку и вручную блокировать/разблокировать мьютекс, тогда как std::lock_guard блокирует сразу и не дает возможности управления.

- Перемещение: std::unique_lock поддерживает перемещение, что позволяет передавать владение блокировкой, std::lock_guard не поддерживает это.

- Накладные расходы: std::unique_lock может быть немного тяжелее std::lock_guard из-за дополнительной функциональности.

Выбор между ними зависит от необходимости: если нужна простая автоматическая блокировка без излишней сложности, подходит std::lock_guard. Для более гибкого управления блокировкой используйте std::unique_lock.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
🔥 Что такое абстрактный класс?

«Абстрактный класс» в C++ — это класс, содержащий хотя бы одну чисто виртуальную функцию. Такой класс не может быть инстанцирован напрямую и служит основой для создания производных классов, которые реализуют чисто виртуальные функции.

Например:


class Shape {
public:
virtual void draw() = 0; // Чисто виртуальная функция
};


В этом примере Shape — абстрактный класс с чисто виртуальной функцией draw(). Производные классы должны предоставить свою реализацию этой функции:


class Circle : public Shape {
public:
void draw() override {
// Реализация рисования круга
}
};

class Rectangle : public Shape {
public:
void draw() override {
// Реализация рисования прямоугольника
}
};


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

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥1
🔥 Как использовать std::thread для многопоточности?

В C++ для реализации многопоточности используется класс std::thread из стандарта C++11. Он позволяет запускать функции в отдельных потоках.

Например, запуск функции в новом потоке:


#include <iostream>
#include <thread>

void work() {
// Некоторые действия
std::cout << "Привет из потока!" << std::endl;
}

int main() {
std::thread t(work); // Запуск функции work в новом потоке
t.join(); // Ожидание завершения потока
return 0;
}


В этом примере создается поток t, который выполняет функцию work(). Метод join() блокирует текущий поток до завершения потока t.

Можно передавать параметры в функцию потока:


void work(int value) {
// Использование переданного значения
std::cout << "Значение: " << value << std::endl;
}

int main() {
int num = 42;
std::thread t(work, num); // Передача аргумента в функцию потока
t.join();
return 0;
}


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


#include <mutex>

std::mutex mtx;

void work() {
mtx.lock(); // Захват мьютекса
// Критическая секция
mtx.unlock(); // Освобождение мьютекса
}


Мьютексы предотвращают одновременный доступ к данным из разных потоков, избегая гонок данных.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
C++ собеседования pinned «Подписывайся на наши новые каналы! 👩‍💻 Git 🖥 SQL 👩‍💻 QA»
🔥 Расскажи про основные команды в makefile

Makefile используется для автоматизации процесса сборки программ. Основные команды (или правила) в Makefile определяются в формате:


цель: зависимости
команды


Ниже приведен простой Makefile:


all: program

program: main.o utils.o
g++ main.o utils.o -o program # Компоновка объектных файлов в исполняемый файл

main.o: main.cpp
g++ -c main.cpp -o main.o # Компиляция main.cpp в объектный файл

utils.o: utils.cpp
g++ -c utils.cpp -o utils.o # Компиляция utils.cpp в объектный файл

clean:
rm -f *.o program # Удаление объектных файлов и программы


В этом Makefile определены следующие цели:

- all: цель по умолчанию, которая зависит от program.
- program: зависит от main.o и utils.o, осуществляет линковку.
- main.o и utils.o: компилируют исходные файлы в объектные.
- clean: удаляет сгенерированные файлы.

Команды выполняются, только если зависимости новее цели. Это обеспечивает эффективную сборку, пересобирая только измененные части кода.

Makefile позволяет автоматизировать и управлять процессом сборки, делая его более организованным и масштабируемым, особенно в больших проектах.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🔥 Объясни разницу между ссылками и указателями

Разница между ссылками и указателями в C++ заключается в их использовании и поведении.

Ссылки являются альтернативными именами для существующих переменных. После инициализации ссылка всегда ссылается на один и тот же объект и не может быть переназначена на другой.


int a = 5;
int& ref = a; // Ссылка на переменную a
ref = 10; // Изменяет значение a на 10


Указатели хранят адреса переменных и могут быть переназначены для указания на другие объекты. Указатель может быть nullptr или указывать на неинициализированную память.


int a = 5;
int* ptr = &a; // Указатель на переменную a
*ptr = 10; // Изменяет значение a на 10

int b = 20;
ptr = &b; // Теперь ptr указывает на b


Основные отличия:

- Инициализация: Ссылки должны быть инициализированы при объявлении. Указатели могут быть инициализированы позже или быть nullptr.

- Переназначение: Ссылки не могут изменить объект, на который ссылаются. Указатели могут переназначаться на другие адреса.

- Нулевые значения: Ссылки не могут быть нулевыми или несвязанными. Указатели могут быть nullptr.

- Операции разыменования: Для доступа к значению по указателю используется оператор *. Ссылки позволяют обращаться к переменной напрямую без специальных операторов.

Ссылки обеспечивают более безопасный и простой синтаксис, особенно при передаче параметров в функции. Указатели предоставляют больший контроль и гибкость при работе с памятью, но требуют более тщательного управления для предотвращения ошибок, таких как утечки памяти или разыменование nullptr.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🔥 Объясни использование constexpr

constexpr появилась в C++11 и используется для выполнения вычислений на этапе компиляции. Это позволяет создавать константные выражения и оптимизировать код.

Пример использования constexpr функции:


constexpr int square(int x) {
return x * x;
}

constexpr int value = square(5); // Вычисляется во время компиляции

int array[value]; // Массив размером 25


В этом примере функция square вычисляет квадрат числа во время компиляции, и переменная value получает значение 25.

Начиная с C++14, constexpr функции могут содержать более сложную логику:


constexpr int factorial(int n) {
return n <= 1 ? 1 : (n * factorial(n - 1));
}

static_assert(factorial(5) == 120, "Неверное вычисление факториала");


Здесь функция factorial рекурсивно вычисляет факториал числа во время компиляции.

constexpr может быть применен к переменным:


constexpr double pi = 3.1415926535;


А также к конструкторам и методам классов:


class Point {
public:
constexpr Point(double x, double y) : x_(x), y_(y) {}
constexpr double getX() const { return x_; }
constexpr double getY() const { return y_; }
private:
double x_;
double y_;
};

constexpr Point origin(0.0, 0.0);


Использование constexpr позволяет:

- Выполнять проверки во время компиляции с помощью static_assert.
- Улучшать производительность за счет вычислений на этапе компиляции.
- Создавать константные выражения для инициализации констант, размеров массивов и параметров шаблонов.

Важно помнить, что для успешного использования constexpr, все функции и выражения внутри него также должны быть constexpr или доступны на этапе компиляции.

Ставь 👍, если было полезно!
Еще больше ответов для подготовки к собеседованиям на сайте 👈
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6