반응형
용어 설명
얕은 복사 복사 대상이 주솟값이므로 참조하는 값이 서로 같다. 따라서 원본 값이 바뀌면 복사한 값도 바뀐 값을 참조한다.
깊은 복사 서로 다른 독립적인 메모리에 실제 값가지 복사하는 것이다.(컨테이너의 여러개의 원소를 복사해야하는 경우 표준 라이브러리의 copy 함수를 활용하면 코드의 간결함과 성능까지 확보할 수 있다.)
난수 생성 1. <random> 헤더 파일의 32bit 버전의 std::mt19937, 64bit 버전의 std::mt19937_64
2. 시간을 시작 숫자(시드값)로 활용하여 난수 생성
3. <random> 헤더 파일의 random_device 를 사용, 하드웨어 엔트로피를 시작 숫자(시드값)으로 활용하여 난수 생성
컨셉(Concept) 템플릿의 타입에 “어떤 연산이 가능한가”를 명시적으로 제약하는 기능으로,
코드의 안정성, 가독성, 컴파일 오류 가독성을 모두 향상시키는 C++20의 핵심 기능이다.

예시)
#include <concepts>   // concept 사용을 위해 필요
#include <iostream>

template <std::integral T>  // ✅ 정수형만 허용
T add(T a, T b) {
    return a + b;
}

int main() {
    std::cout << add(3, 5) << '\n';   // OK
    // std::cout << add(3.2, 4.5);   // ❌ 컴파일 오류: double은 integral 아님
}
코루틴(Coroutine) co_yield, co_await, co_return 을 이용해
함수 실행을 중단하고 재개할 수 있는 구조로,
비동기 처리, 지연 계산, 제너레이터를 효율적으로 구현할 수 있게 해준다.
스레드보다 훨씬 가볍고 빠름 (컨텍스트 스위칭 없음)
모나드(Monad) “값을 감싼 컨테이너”로,
연산을 안전하게 연결(bind) 하여 에러나 부작용을 최소화하는 함수형 설계 패턴이다.
C++에서는 std::optional, std::future, Result 등이 대표적인 모나드 구현체이다.
함수 포인터 콜백을 구현할 때 자주 사용됩니다. 프로그램에서 다른 함수에 의해 특정한 실행이 필요할 때 호출되는 함수

예시 1)
#include <iostream>
using namespace std;

void process(int x, int y, int (*op)(int, int)) {
    cout << "결과: " << op(x, y) << endl;
}

int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }

int main() {
    process(2, 3, add); // 함수 포인터 전달
    process(2, 3, mul);
}

예시 2)
#include <iostream>
using namespace std;

class MyClass {
public:
    void hello() { cout << "Hello!" << endl; }
    void bye()   { cout << "Goodbye!" << endl; }
};

int main() {
    MyClass obj;

    // 멤버 함수 포인터 선언
    void (MyClass::*fp)();

    // hello 함수 주소 저장
    fp = &MyClass::hello;
    (obj.*fp)();   // 호출 방식 (중요!)

    // bye 함수 주소 저장
    fp = &MyClass::bye;
    (obj.*fp)();   // 호출
}
함자 1. 함수 객체를 의미 한다. 즉 함수처럼 호출할 수 있는 객체를 말한다.
2. 함수 호출 연산자 operator() 를 오버로딩하여 정의한다.

예시)
#include <iostream>

using namespace std;

struct bomb {
  void operator()() {
    cout << "꽝!" << endl;
  }

  void operator()(int range) {
    cout << "반경 " << range << "m내 플레이어 공격!" << endl;
  }
};

int main() {
  bomb mine;

  mine();
  mine(30);

  return 0;
}
   

 

반응형

'Programming Language > C++' 카테고리의 다른 글

시간 복잡도  (0) 2025.11.05
컨테이너와 반복자  (0) 2025.11.05
템플릿  (0) 2025.11.03
객체지향 설계 원칙  (0) 2025.11.03
다형성을 활용한 디자인 패턴  (0) 2025.11.03
반응형

함수 템플릿

  • 함수 하나로 다양한 형식의 데이터를 같은 알고리즘으로 처리할 수 있다.
  • 개방 폐쇄 원칙(OCP)을 지키면서 여러가지 용도로 널리 쓸 수 있는 함수를 만드는 방법이다.
  • 매개변수의 데이터 형식을 함수를 작성하는 시점이 아닌, 사용(호출)하는 시점에 정할 수 있다.
  • 함수 템플릿이 포함된 소스 코드를 컴파일하면 해당 함수에 사용된 데이터 형식으로 함수의 실제 구현체가 만들어진다.
  • 모든 데이터 형식에 대응할 수 있는 알고리즘으로 정의해야한다. 그렇지 않으면 컴파일 오류가 발생한다.
  • 컴파일러는 함수 템플릿을 호출하는 구문을 만나면 인자로 전달한 값으로 템플릿 매개변수의 데이터 형식을 추론하고, 이 형식으로 완성된 함수를 오브젝트 코드로 만든다. 이 과정을 템플릿의 인스턴스화 라고 한다.
  • 템플릿 매개변수의 데이터 형식을 명시해 함수를 호출하면 컴파일러가 데이터 형식을 추론하지 않고 해당 형식으로 변환한 후에 곧바로 인스턴스화한다. 즉 형식 추론은 시간이 많이 소요되는 작업이기 때문에 명시적 호출을 지향한다.
  • 특정 데이터 형식만 다른 알고리즘으로 처리하게 할 수 있다. 이를 템플릿 특수화라고 한다. 함수 템플릿은 명시적 특수화, 부분 특수화 중 명시적 특수화만 사용할 수 있다.
  • 컴파일러가 함수 호출을 처리할 때는 오버로딩 해석 과정을 거치기 때문에 부분 특수화는 금지시켰다. 즉 오버로딩으로 해결이 가능하기 때문이다.

작업 예시

  • 명시적 특수화
#include <iostream>
#include <string>

using namespace std;

template <typename T>
T data_sum(T operand1, T operand2) {
  return operand1 + operand2;
}

// 템플릿 타입이 double 일 경우 실행할 함수를 재정의
template <>
double data_sum(double operand1, double operand2) {
  return  (int)operand1 + (int)operand2;
}

int main() {
  int data1 = 3, data2 = 5;
  double data3 = 4.5, data4 = 8.9;
  string data5 = "Hello, ", data6 = "World!";

  cout << "정수형 데이터 합: " << data_sum(data1, data2) << endl;
  cout << "실수형 데이터 합: " << data_sum(data3, data4) << endl;
  cout << "문자열 데이터 합: " << data_sum(data5, data6) << endl;

  return 0;
}

/*
실행 결과

정수형 데이터 합: 8
실수형 데이터 합: 12
문자열 데이터 합: Hello, World!
*/

클래스 템플릿

  • 템플릿 매개변수를 활용해 다양한 형식에 대응할 수 있는 범용 클래스를 만드는 방법이다.
  • 클래스 템플릿에서는 객체를 생성할 때 템플릿 매개변수의 형식을 명시해주어야 한다.(C++ 17 이후 컴파일러에서는 형식 추론이 가능하지만 컴파일러는 템플릿 매개변수의 형식을 완벽하게 추론해 낼 수 없기 때문에 직접 명시하는 것을 지향한다.)
  • 템플릿 매개변수의 일부만 지정할 수 있는 부분 특수화를 이용할 수 있다.
  • 클래스 템플릿의 선언과 정의를 별도의 파일로 분리하면 안되며, 한 파일에 있어야 한다. 왜냐하면 템플릿은 컴파일 시점에 인스턴스화 되기 때문에 다른 파일에 있을 경우 링크 오류가 발생한다.

작업 예시

  • 부분 특수화
#include <iostream>

using namespace std;

template <typename Type1, typename Type2>
class data_package {
public:
  data_package(Type1 first, Type2 second) : first(first), second(second) {}
  void print_out_element() {
    cout << "첫 번째 요소: " << first <<
      ", 두 번째 요소: " << second << endl;
  }
private:
  Type1 first;
  Type2 second;
};

// 부분 특수화 첫번째 매개변수는 string으로 고정하고 두번째만 템플릿 매개변수로 사용
template <typename T>
class data_package<string, T> {
public:
  data_package(string first, T second) : first(first), second(second) {}
  void print_out_element() {
    cout << first << "과 함께 입력된" <<
      ", 두 번째 요소: " << second << endl;
  }
private:
  string first;
  T second;
};
int main() {
  data_package<int, double> template_inst1(5, 10.5);
  data_package<string, int> template_inst2("문자열", 10);

  template_inst1.print_out_element();
  template_inst2.print_out_element();
}

 

반응형

'Programming Language > C++' 카테고리의 다른 글

컨테이너와 반복자  (0) 2025.11.05
용어 정리  (0) 2025.11.04
객체지향 설계 원칙  (0) 2025.11.03
다형성을 활용한 디자인 패턴  (0) 2025.11.03
프로그래밍 패러다임  (0) 2025.10.30
반응형

Solid 원칙

소프트웨어의 유지 보수와 확장성에 도움이 되는 다섯 가지 원칙이다.

단일 책임 원칙(Single Responsibility Principle : SRP)

  • 클래스는 한 가지 기능만 수행해야 하고, 한 가지 이유로만 변경해야 한다. 즉, 어떤 클래스가 A 라는 기능을 수정할 때도 변경되고, B라는 기능을 수정할 때도 변경되는 현상을 지양해야 한다는 의미이다.
  • 변경 사항이 한 클래스에 국한되는 것변경된 클래스가 다른 클래스에 영향을 주지 않는것, 이 두 가지가 핵심이다.
  • 다중 상속이 필요한 상황에서 컴포지션, 어그리게이션은 단일 책임 원칙을 지켜 수정 범위를 한 클래스에 갇히게 하는 좋은 방법이다.

개방 폐쇄 원칙(Open-Closed Principle : OCP)

  • 확장에 열려(개방)있고 수정에 닫혀(폐쇄) 있어야 한다.
  • 추상 클래스(인터페이스)를 통해 구현할 수 있다.
  • 프로그램에서 주요 기능의 흐름은 추상 클래스를 활용해 작성하고 이를 상속받아 구현하는 클래스에 따라서 세부 동작이 결정되게 한다.이러한 설계 패턴을 템플릭 메서드 패턴 이라고 한다. 즉 추상 클래스에 주요 기능을 모두 가상 함수로 선언하고 이를 상속 받는 자식(구현) 클래스에서 가상 함수를 각각 구현한다. 그리고 템플릿 함수(예시. 전역 함수이면서 파라미터로 부모 클래스를 받는 함수)에서 자식 클래스의 객체에 오버라이딩된 가상 함수를 호출해 논리의 흐름을 완성. 확장이 필요하면 자식 클래스를 추가한다.

리스코프 치환 원칙(Liskov Substitution Principle : LSP)

  • 자식 클래스는 부모 클래스를 대체할 수 있어야 한다.
  • 부모 클래스를 상속받아 구현한 자식 클래스는 부모 클래스로 업캐스팅이 가능하다.
  • 자식 클래스에서 부모 클래스의 멤버 함수를 상속받아 오버라이딩하거나 유지해야 한다.

인터페이스 분리 원칙(Interface Segregation Principle : ISP)

  • 단일 책임 원칙을 인터페이스에 적용한 것으로 생각하면 이해가 쉽다.
  • 인터페이스는 작고 섬세해야 하고, 클래스는 필요한 인터페이스만 구현해야 한다.

의존성 역전 원칙(Dependency Inversion Principle : DIP)

  • 상위 수준 모듈은 하위 수준의 모듈에 의존해서는 안되며 상위, 하위 수준 모두 추상레이어(인터페이스)에 의존해야 한다.
  • 개방 폐쇄 원칙을 적용하기 위해 사용된다.
  • 특정 클래스에 클래스가 아닌 필요한 인터페이스를 어그리게이션함으로써 인터페이스에 의존하도록 설계가 가능하다.

 

반응형

'Programming Language > C++' 카테고리의 다른 글

용어 정리  (0) 2025.11.04
템플릿  (0) 2025.11.03
다형성을 활용한 디자인 패턴  (0) 2025.11.03
프로그래밍 패러다임  (0) 2025.10.30
예외 처리  (0) 2025.10.30
반응형

전략 패턴(Strategy Pattern)

  • 하나의 행동(알고리즘)을 여러 방식으로 교체할 수 있게 하는 패턴. 즉 객체의 행위를 런타임에 바꿀 수 있도록 전략을 분리한다.
  • 같은 기능을 다른 알고리즘으로 정의하고 싶을 때 각각을 캡슐화하여 교체할 수 있게 하는 것이며, 소프트웨어의 유지 보수성을 높이고 새로운 알고리즘을 추가하기도 쉽다.

작업 예시

#include <iostream>
#include <memory>
using namespace std;

// 전략 인터페이스
struct MoveStrategy {
    virtual void Move() = 0;
    virtual ~MoveStrategy() = default;
};

// 구체적인 전략들
struct WalkMove : MoveStrategy {
    void Move() override { cout << "Walking...\n"; }
};

struct FlyMove : MoveStrategy {
    void Move() override { cout << "Flying...\n"; }
};

// Context
class Character {
    unique_ptr<MoveStrategy> strategy;
public:
    Character(unique_ptr<MoveStrategy> s) : strategy(move(s)) {}
    void Move() { strategy->Move(); }

    void SetStrategy(unique_ptr<MoveStrategy> s) {
        strategy = move(s);
    }
};

int main() {
    Character c(make_unique<WalkMove>());
    c.Move(); // Walking...

    c.SetStrategy(make_unique<FlyMove>());
    c.Move(); // Flying...
}

팩토리 패턴(Factory Pattern)

  • 객체 생성 과정을 감추고, 타입 선택을 유연하게 하는 패턴. 즉 객체를 직접 new 하지 않고, '무엇을 만들지'를 팩토리 클래스에 위임한다.
  • 객체를 일정한 규칙으로 생성할 수 있으며 이와 관련한 복잡한 로직을 캡슐화하여 시스템의 확장성을 높이고 변화에 대응하기가 쉽다.

작업 예시

#include <iostream>
#include <memory>
using namespace std;

// Product 인터페이스
struct Weapon {
    virtual void Attack() = 0;
    virtual ~Weapon() = default;
};

// 구체적인 제품들
struct Sword : Weapon {
    void Attack() override { cout << "Swing sword!\n"; }
};

struct Bow : Weapon {
    void Attack() override { cout << "Shoot arrow!\n"; }
};

// Factory
class WeaponFactory {
public:
    static unique_ptr<Weapon> CreateWeapon(const string& type) {
        if (type == "sword") return make_unique<Sword>();
        else if (type == "bow") return make_unique<Bow>();
        return nullptr;
    }
};

int main() {
    auto weapon = WeaponFactory::CreateWeapon("sword");
    weapon->Attack(); // Swing sword!
}

두가지 패턴 비교

구분  전략 패턴 팩토리 패턴
초점 “행동 교체” “객체 생성”
시점 런타임 (행동 변경) 컴파일 or 런타임 (생성 시 결정)
구성 요소 Context + Strategy Factory + Product
목적 같은 객체가 다른 행동을 가질 수 있게 어떤 객체를 만들지 결정
다형성 사용 행동(메서드) 위주 타입(객체 종류) 위주
예제 AI 이동 전략, 정렬 알고리즘 선택 무기 생성, UI 위젯 생성

 

비유 상황 전략 패턴  팩토리 패턴
게임 캐릭터 “걷기 ↔ 달리기 ↔ 날기 전략 교체” “전사 ↔ 궁수 ↔ 마법사 객체 생성”
자동차 “운전 모드 (스포츠 ↔ 에코) 변경” “세단 ↔ SUV ↔ 트럭 생성”
실제 공장 생산 방법을 바꾸는 것 어떤 제품을 생산할지 결정하는 것
반응형

'Programming Language > C++' 카테고리의 다른 글

템플릿  (0) 2025.11.03
객체지향 설계 원칙  (0) 2025.11.03
프로그래밍 패러다임  (0) 2025.10.30
예외 처리  (0) 2025.10.30
레퍼런스 변수  (0) 2025.10.30
반응형

프로그래밍 패러다임

  • 프로그램을 어떤 절차와 구조로 만들 것인지에 대한 스타일이나 접근 방법을 나타내며, 언어가 지원하는 기능, 코드의 구조, 문제 해결 접근 방식 등에 차이가 있다.
  • 종류로는 비구조적 프로그래밍, 절차적 프로그래밍, 객체지향 프로그래밍이 있다.

비구조적 프로그래밍

  • 코드를 구조화하지 않고 작성하는 방법으로 프로그래밍 하는 것이다.
  • 첫번째 줄부터 마지막 줄까지 차례대로 실행되며, 코드의 흐름을 이동하는 goto 문을 사용하는 특징이 있다.
  • 대표적인 언어로는 어셈블리어, 초창기의 포트란이 있다.

절차적 프로그래밍

  • 소스 코드를 여러 부분으로 나눠서 활용하는 패러다임으로 프로시저(함수)를 이용해 구조화하는 방식이다.
  • 코드의 논리 구조를 모듈화하여 재사용할 수 있으며, 라이브러리처럼 누군가가 만들어 놓은 기능을 사용하여 개발도 가능하다.
  • 프로그램이 수행할 기능을 프로시저라는 단위로 쪼개어 문제를 해결하는 하향식(top-down)방법이다.(하향식 방법은 도시에 행정 구역을 나누는 것으로 이해)
  • 대표적인 언어로는 C, 코볼(cobol), 포트란이 있다.

절차적 프로그래밍에 한계

  • 프로그램의 규모가 커지면 흐름 코드가 복작해지며 프로시저 (함수) 도 대폭 늘어난다. 또한 프로시저 간의 관계도 복잡해진다.(객체지향 프로그래밍에 추상화, 다형성)
  • 다층 구조를 포현할 방법이 없다.(객체지향 프로그래밍에 상속성)
  • 직접 접근하지 말아야 할 프로시저나 전역 변수에 접근을 막을 수 없다.(객체지향 프로그래밍에 캡슐화)

객체지향 프로그래밍

  • 객체라는 논리적인 개념으로 코드를 구성하고, 다양한 객체 간의 관계를 구성할 수 있다.
  • 논리적인 단위를 먼저 정의한 후에 이를 조합해 프로그램이 수행할 기능을 만드는 상향식(bottom-up)방법이다.(상향식 방법은 레고 블록을 쌓아 도시를 만드는 것으로 이해)

객체지향 프로그래밍의 특징

1. 추상화 : 현실 세계의 사물을 모델링하여 객체로 만들 때, 어떤 부류에서 불필요한 요소는 배제하고 공통된 특징만 추출하는 것

  - 장점 : 클래스로 만들면 코드의 불필요한 부분을 줄이고 범용성과 재사용성을 높일 수 있다.

 

2. 캡슐화 : 복잡한 내부 기능을 묶어 외부에서 불필요한 정보를 감추는 것(접근 지정자로 정보를 은닉화 하는 것)

  - 장점 : 프로그램의 복잡도는 낮아지고 재사용성을 높일 수 있다.

 

3. 상속성 : 다양한 특성으로 추상화되고 캡슐화한 클래스를 확장하고 변형하는 것.(부모 객체의 특성을 이어받는 것) 

  - 장점 : 상속을 통해 논리적인 포함 관계와 공통의 특징을 더 명확하게 모델링할 수 있다.

 

4. 다형성 : 자식 객체는 부모 객체의 역할을 대신할 수 있다. 상속 관계의 객체에서 같은 기능(함수)이 다르게 동작하는 특성

  - 장점 : 기능이 확장, 변경되어도 소스 코드 변경을 최소화할 수 있다.

 

반응형

'Programming Language > C++' 카테고리의 다른 글

객체지향 설계 원칙  (0) 2025.11.03
다형성을 활용한 디자인 패턴  (0) 2025.11.03
예외 처리  (0) 2025.10.30
레퍼런스 변수  (0) 2025.10.30
정적 변수와 상수 변수  (0) 2025.10.30
반응형

예외 처리

  • 예외 처리를 해두면 예기치 못한 상황에서도 유연하게 대처할 수 있다.
  • 프로그램의 안정성을 높이고 설사 오류가 발생하더라도 비정상으로 종료되지 않도록 한다.
  • catch(...) 문으로 기타 예외를 처리할 수 있다.
  • catch 문으로 받지 못하는 예외를 던질 경우 런타임 오류가 발생하며 프로그램이 강제로 종료된다.
  • 함수에서 예외가 처리되지 않는 경우 함수를 호출한 쪽으로 전달되는 현상을 스택 풀기라고 하며, 이를 이용하여 함수에 예외가 처리된다.
  • 형식
    • try : 예외가 발생할 수 있는 코드 블록을 중괄호 {}로 감싼다.
    • throw : 예외를 catch 블록으로 던진다.
    • catch : throw로 던진 예외를 받아서 처리한다.
#include <iostream>

using namespace std;

void func_throw() {
  cout << "func_throw()" << endl;
  cout << "throw -1" << endl;
  throw - 1;   // 정수 형식 예외 던지기
  cout << "after throw -1" << endl; // 실행되지 않음.
}

int main() {
  try {
    func_throw();
  }
  catch (int exec) {   // 정수 형식 예외 받기
    cout << "catch " << exec << endl;
  }

  return 0;
}

/*
출력 결과

func_throw()
throw -1
catch -1
*/

어설션(assertion)을 이용한 예외처리

  • 디버그 모드에서 오류가 생길 수 잇는 부분을 검사할 수 있는 매크로이다.
  • 예상치 못한 상황에서 프로그램 동작을 중단시키는 도구이다.
  • assert 는 디버그 모드에서만 컴파일되므로 다른 코드에 영향을 주지 않는 코드로만 작성해야된다. 예를 들어 릴리즈 모드에서 영향을 주는 코드는 작성하지 않도록 한다.

예외 처리 생략

  • 함수가 예외를 던지지 않음을 명시하면 컴파일러가 코드를 최적화하고 빠르게 실행하는 데에 도움이 된다.
  • noexcept 키워드를 사용한다.

예외 처리 생략 작업 예시

  • 설명) 함수가 예외를 던지지 않음을 명시. func 함수에서 예외를 던질 경우 컴파일 경고가 발생한다.
int func() noexcept
  • 설명) 함수가 예외를 던지는지 확인. func 함수에 예외를 던지는지 확인해 true, false를 리턴한다.
bool does_not_throw = noexcept(func());

예외 처리 실패 대응

  • 종료 처리 함수를 설정하는 set_terminate로 프로그램이 강제 종료되기 전에 특정 동작을 수행하도록 구성할 수 있다.
  • 프로그램이 종료될 때는 내부적으로 terminate라는 런타임 함수에서 프로그램을 강제로 종료시키는 abort 함수가 호출된다.
  • exit 함수 : 상태 코드 0을 전달하면 프로그램을 정상으로, -1을 전달하면 비정상으로 종료한다.
  • abort 함수 : 어떤 정리 작업도 수행하지 않은 채 프로그램을 비정상으로 즉시 종료한다.
#include <iostream>
#include <cstdlib>  // exit와 set_terminate 함수 사용을 위해 추가

using namespace std;

// 종료 처리 함수 
void myterminate() {
  cout << "myterminate called" << endl;
  exit(-1);      // 프로그램을 비정상적으로 종료
}

int main(void) {
  set_terminate(myterminate);    // 종료 처리 함수를 myterminate로 지정

  throw 1;    // 처리되지 않는 예외를 던짐

  return 0;   // 이 줄은 실행되지 않음, 위에서 예외가 던져졌기 때문
}

 

반응형

'Programming Language > C++' 카테고리의 다른 글

다형성을 활용한 디자인 패턴  (0) 2025.11.03
프로그래밍 패러다임  (0) 2025.10.30
레퍼런스 변수  (0) 2025.10.30
정적 변수와 상수 변수  (0) 2025.10.30
함수와 구조체  (0) 2025.10.30

+ Recent posts