Skip to content

Latest commit

 

History

History
325 lines (213 loc) · 26.8 KB

File metadata and controls

325 lines (213 loc) · 26.8 KB

C++ 질문 대비

👉 빠른 이동


💡 객체 지향에 대해 설명하세요.

객체지향은 소프트웨어 개발 방법론중 하나로, 프로그래밍에서 데이터와 그 데이터를 처리하는 데 필요한 연산들을 객체라는 단위로 조직화 하는 것을 말한다. 객체 지향 프로그래밍은 실세계 사물을 모델링하여 프로그램을 더 직관적으로 설계할 수 있게 해준다.

  • 캡슐화

    객체는 데이터와 기능을 하나의 단위로 묶는다. 이를 통해 데이터 구조와 데이터를 조작하는 방법을 결합하여 데이터의 무결성을 보장하고, 외부에서의 무분별한 접근을 제한한다. 즉 낮은 결합도를 유지하도록 설계하며, 정보 은닉을 할 수 있다.

  • 상속

    한 클래스의 특성(데이터와 메서드)을 다른 클래스가 물려받을 수 있다. 이는 코드의 재사용성을 높이고 계층적 분류가 가능하게 해준다. 공통된 특성을 하나의 개념으로 정립

  • 다형성

    같은 인터페이스나 메서드가 다양한 형태로 동작할 수 있다. 예를 들어, 다른 클래스의 객체들이 같은 메시지에 대해 다른 각기 다른 방식으로 응답할 수 있다. 다른 클래스의 객체가 같은 메시지를 받았을 때 각자 방식으로 변환하는 것

  • 추상화

    복잡한 현실 세계의 사물이나 개념을 단순화하는 과정이다. 중요한 정보만(필요로하는 속성)을 추출하여 프로그램 내의 객체로 표현한다.


💡 클래스와 객체, 인스턴스에 대해 설명하세요.

  • 클래스: 객체를 만들어내기 위한 설계도 혹은 틀
  • 객체: 소프트웨어 세계에 구현할 대상, 클래스에 선언된 모양 그대로 생성된 실체, 클래스의 인스턴스라고도 부른다.
  • 인스턴스: 설계도를 바탕으로 소프트웨어 세계에 구현된 구체적인 실체, 인스턴스는 객체에 포함된다고 볼 수 있다.

💡 다형성은 무엇이고 C++에서 어떻게 구현되나요?

다형성은 같은 인터페이스 함수 호출이 서로 다른 객체에 대해 다른 동작을 수행 할 수 있게 하는 개념이다. C++에서는 주로 가상함수를 사용하여 다형성을 구현한다. 가상함수를 사용하면, 파생 클래스에서 재정의 된 함수가 실행된다.


💡 절차적 프로그램과 객체지향의 차이를 설명하세요.

  • 절차적 프로그래밍은 프로그램이 수행해야 할 일련의 절차나 작업을 순서대로 나열하는 방식입니다. 프로그램은 함수의 집합으로 구성되어 있으며 각 함수는 특정 작업을 수행하고, 데이터는 전역 변수나 지역 변수를 통해 함수 간에 전달됩니다.
  • 객체 지향 프로그래밍은 프로그램을 객체의 집합으로 바라보는 방식입니다. 각 객체는 데이터와 이 데이터를 조작하는 메소드를 포함하고 있습니다. 이 패러다임에서는 데이터와 함수를 캡슐화하여 객체를 내부에 숨기고, 객체 간에는 메시지를 통해 소통합니다.

    두 프로그래밍 패러다임의 주요 차이점은 데이터와 함수의 구조에 있습니다. 절차적 프로그래밍에서는 함수가 중심이 되며 데이터는 별도로 관리 됩니다. 그러나 객체 지향 프로그래밍에서는 데이터와 관련 함수가 하나의 '객체'로 묶여있어, 보다 구조화된 방식으로 프로그램을 구성할 수 있습니다. 이로 인해 객체지향 프로그래밍은 재사용성, 유지보수성, 모듈성 측면에서 더 유리하다고 할 수 있습니다.


💡 오버로딩과 오버라이딩의 차이를 설명하세요.

Overloading: 함수 중복 정의 / Overriding: 함수 재정의

오버로딩은 메소드 이름은 같은 함수를 중복 정의 하는 것이다. 파라미터 개수, 파라미터의 자료형에 따라 여러개의 중복 이름의 함수를 만들 수 있다. 오버 라이딩은 상속 관계에서 함수를 재정의할 때 사용된다. 상속받았을 때 부모 클래스의 함수를 사용하지 않고 다른 기능을 실행할 때 함수를 자식클래스에 같은 이름, 같은 자료형으로 재정의 해서 사용한다.


💡 STL은 무엇이며, 대표적인 컨테이너들의 특징을 설명하세요.

STL은 표준 템플릿 라이브러리로 알고리즘, 컨테이너, 함수자, 반복자등 다양한 프로그래밍 구성 요소를 제공한다. STL을 사용하면 데이터 구조와 알고리즘을 쉽게 사용할 수 있다.

  • 컨테이너: 다양한 데이터 구조, 벡터, 리스트, 맵 등...
  • 알고리즘: 정렬, 검색, 변환 등
  • 반복자(Iterator): 컨테이너의 데이터를 순회할 수 있게 해주는 객체, 포인터와 유사한 개념으로, 컨테이너 내의 데이터에 접근하고 순회하는 데 사용한다.
  • 함수자: 함수처럼 동작하는 객체

"STL은 템플릿 기반으로 작성되어 있어, 다양한 데이터 타입에 대해 유연하게 사용할 수 있다. 이를 활용하여 코드의 재사용성과 유지보수성이 향상된다."

  1. Vector

    동적 배열을 구현한 컨테이너로, 요소들이 메모리 상에서 연속적으로 배치되어 있어, 인덱스를 통한 빠른 접근이 가능하다. 크기가 가변적이며, 끝 부분에 요소를 추가하거나 제거하는 작업이 효율적이다. 그러나 중간에 요소를 삽입하거나 제거하는 경우 비효율적이다. 일반적으로 순차적인 접근이 필요한 경우에 사용된다. (빠른 임의 접근이 필요할때 사용)

  2. List

    양방향 연결 리스트로 구현된 컨테이너이다. 요소 삽입과 삭제가 빠르지만, 임의 접근에는 비효율적이다(인덱스를 통한 접근이 불가). 특정 요소에 접근하기 위해서는 처음부터 순자적으로 탐색해야한다. 주로 요소의 삽입과 삭제가 빈번하게 일어나는 경우 사용된다.

  3. Map

    키-값 쌍을 저장하는 연관 컨테이너이다. 내부적으로는 균형 이진 트리(레드-블랙 트리)를 사용하여 요소를 저장한다. 이로 인해 삽입, 삭제, 검색 작업이 로그 시간 "O(logN)"복잡도를 가진다. 맵은 요소들이 키에 따라 자동으로 정렬된다. 정렬된 키-값 쌍이 필요할 때 사용

  4. Unordered Map(Hash Map)

    언오더드 맵은 해시테이블을 기반으로 하는 연관 컨테이너이다. 키를 해시하여 해당 해시 버킷에 값을 저장한다. 이는 평균적으로 상수 시간 복잡도를 가지는 빠른 접근과 검색, 삽입, 삭제 작업을 가능하게 합니다. 그러나 언오더드 맵은 요소들이 키에 따라 정렬되지 않습니다. 빠른 접근이 중요하지만 정렬은 필요 없을 때 적합하다.

  5. Set

    집합을 구현한 컨테이너로, 중복을 허용하지 않고 요소가 정렬된 상태로 저장된다. 주로 중복을 허용하지 않는 유일한 요소들의 집합을 관리할 때 사용된다.

템플릿이란?

C++에서 타입에 독립적인 코드를 작성할 수 있게 해주는 기능. 템플릿을 사용하면 하나의 함수나 클래스 코드로 다양한 데이터 타입을 다룰 수 있다.


💡 생성자(Constructor)와 소멸자(Destructor)에 대해 설명하세요.

  • 생성자

    생성자 함수를 이용하여 객체를 생성과 동시에 멤버 변수를 초기화 할 수 있다. 생성자는 클래스 이름과 동일한 이름으로 구현되며, 생성자를 따로 구현하지 않는다면 객체 생성시 멤버 변수가 NULL로 초기화 된다.

  • 소멸자

    객체 사용이 끝났을 때 호출되는 함수이다. 객체의 메모리 반환 위해 사용한다. 클래스 이름 앞에 ~ 표시를 붙은 형태이다.

default constructor

생성자를 정의하지 않은 경우 컴파일러에 의해 자동 생성되는 생성자를 'default constructor'이라 한다. 만약, 클래스에 생성자가 하나라도 정의 되었다면 'default constructor'은 생성되지 않는다.


💡 malloc과 new의 차이점을 설명하세요.

'malloc'와 'new'는 메모리를 동적으로 할당하는 방법이다. 이 둘은 기능적으로 유사하지만 차이점이 몇가지 있다.

  1. malloc는 함수이고, new는 연산자 이다.
  2. malloc는 heap 영역에서 할당되고 new는 dynamic memory에서 할당된다.
  3. malloc는 초기값 지정이 불가능하고, new는 초기값 지정이 가능하다.
  4. new는 개체에서 생성자를 자동으로 호출하고 초기화 해준다.

💡 메모리 누수는 무엇이며, 어떻게 방지할 수 있는가?

메모리 누수는 프로그램이 할당된 메모리 영역을 해제하지 않아 발생하는 문제이다. 이를 방지하기 위해서는 동적으로 할당된 메모리를 적절히 관리해야한다. C++11 이후에는 스마트 포인터 같은 자동 메모리 관리 기능을 사용하여 누수를 방지 할 수 있다.


💡 스마트포인터에 대해 설명하세요.

스마트 포인터는 자원 관리를 자동화하기 위해 사용되는 객체이다. new 키워드를 통해 동적으로 할당 받은 메모리는 반드시 delete 키워드를 사용해 메모리를 해제 해줘야 한다. 하지만 개발자의 실수나 잘못된 설계로 인하여 메모리 해제가 안되는 경우를 방지하고 안전한 사용을 위해 등장한 것이 스마트 포인터이다.

  • std::unique_ptr
    하나의 스마트 포인터만이 특정 객체를 소유할 수 있으며, 소유권을 이전할 수 있다.
  • std::shared_ptr
    여러 스마트 포인터가 동일한 객체를 공유할 수 있으며, 참조 카운팅을 사용하여 자원 관리를 수행한다.
  • std::weak_ptr
    'std::shared_ptr'과 함께 사용되며, 순환 참조를 방지할 때 유용하다. 스마트 포인터는 객체의 생명 주기를 관리하여 메모리 누수를 방지하고, 자동으로 메모리를 해제하는 등의 장점을 가지고 있다.

💡 C++에서 virtual은 왜 존재하는지에 대해 설명하세요.

"C++에서 'virtual'키워드는 가상함수를 정의하는 데 사용된다."

가상함수는 기본 클래스에서 선언되고 파생클래스에서 재정의될 수 있다. 이를 통해 파생클래스는 부모 클래스의 메서드를 자신의 동작에 맞게 변경할 수 있다. 가상함수의 주요 목적은 런타임에 어떤 클래스의 메서드가 호출될지 결정하는 것으로, 이를 통해 동적 바인딩을 구현할 수 있다.

가상함수의 동작 원리에 대해 설명하세요.

C++에서 가상함수를 호출할 때, 함수의 주소는 런타임에 결정된다. 이는 각 객체의 가상함수 테이블을 통해 관리 된다. 객체가 생성될 때, 컴파일러는 각 가상함수에 대한 포인터를 vtable에 추가한다. 함수 호출 시, 프로그램은 vtable을 참조하여 해당 객체 타입에 맞는 올바른 함수 버전을 찾아 실행한다.

가상함수는 C++에서 다형성을 구현하고, 런타임에 함수의 동적 바인딩을 가능하게 하여 유연한 프로그래밍을 가능하게 한다.


💡 가상 소멸자(Virtual Destructor)를 사용해야 하는 이유를 설명하세요.

C++에서 가상 소멸자의 사용은 상속 관계에 있는 클래스들에서 매우 중요하다. 가상 소멸자는 기반 클래스에서 선언되며, 파생 클래스에서 오버라이드될 수 있다. 가상 소멸자의 주된 목적은 파생 클래스의 객체가 기반 클래스의 포인터를 통해 삭제될 때 올바른 소멸자가 호출되도록 하는 것이다.

  • 파생 클래스의 객체가 기반 클래스 포인터를 통해 관리되는 경우, 기반 클래스의 소멸자가 가상이 아니라면 해당 객체가 소멸될 때 파생 클래스의 소멸자가 호출되지 않습니다. 이는 파생 클래스에 할당된 자원이 제대로 해제되지 않아 메모리 누수나 다른 자원 관련 문제를 일으킬 수 있습니다.
  • 가상 소멸자의 작동 방식: 기반 클래스에서 가상 소멸자를 선언하면, 파생 클래스의 객체가 소멸될 때 해당 클래스의 소멸자가 먼저 호출되고, 이어서 기반 클래스의 소멸자가 호출된다. 이로써 객체와 관련된 모든 자원이 올바르게 해제됩니다.

💡 class와 struct의 차이에 대해 설명하세요.

C++에서 클래스와 구조체는 매우 유사하다. 주요 차이점은 기본 접근 제어자 이다. 클래스의 멤버는 기본적으로 Private, 구조체의 멤버는 기본적으로 Public이다. 또한 클래스는 상속, 다형성, 캡슐화 등 객체 지향 프로그래밍의 특성을 지원하는 반면, 구조체는 주로 데이터를 저장하는 데 사용한다.


💡 C++ 빌드 과정에 대해 설명하세요.

소스 코드 작성 -> 전처리 -> 컴파일러 -> 어셈블러 -> 링커 -> 실행 순으로 수행된다

  • 전처리(Preprocessing)
    코드의 주석을 제거하고 define을 치환한다.
  • 컴파일러(Compiler)
    어셈블리 파일로 변환한다.
  • 어셈블러(assembler)
    0과1로 이루어진 오브젝트파일로 변환한다.
  • 링커(linker)
    오브젝트 파일들을 묶어서 실행 코드 파일로 변환한다.

💡 얕은 복사와 깊은 복사의 차이점과 쓰임새에 대해 설명하세요.

  • 얕은 복사
    실제 데이터가 아닌 메모리 주소를 복사한다.
  • 깊은 복사
    변수가 관리하는 리소스 자체를 복사하여 새로운 객체를 만든다.

💡 포인터와 배열의 차이를 설명하세요.

배열은 같은 타입의 요소들이 메모리 상에서 연속적으로 저장된 집합이다. 배열의 이름은 배열의 첫 번째 요소를 가리키는 주소로 사용된다. 포인터는 메모리 주소를 저장하는 변수이다. 포인터는 어떤 타입의 객체든 가리킬 수 있으며, 다른 변수나 객체의 주소를 저장한다.

배열은 동일한 타입의 데이터 집합을 위한 정적 메모리 할당 방식이며, 포인터는 동적 메모리 할당이 가능하고 유연하지만 더 주의 깊게 사용해야 하는 메모리 주소를 가리키는 변수이다.


💡 포인터와 참조의 차이점은 무엇이고, 각각 언제 사용하는 것이 좋은가요?

포인터는 메모리 주소를 저장하는 변수이며, 참조는 다른 변수의 별칭이다. 포인터는 NULL 값을 가질 수 있지만, 참조는 항상 유효한 객체를 참조해야한다. 포인터는 동적 할당, 배열, 다중 포인터 등 복잡한 메모리 관리에서 사용되며 참조는 함수인자 전달이나 클래스 객체의 별칭을 만들 때 주로 사용된다.


💡 Call-by-value & Call-by-ref

  • 값에 의한 호출 (Call-by-Value)

    이 방식에서는 함수에 인자를 전달할 때 인자의 실제 값이 복사된다. 이는 함수 내에서 인자의 값을 변경해도 원본 변수에는 영향을 미치지 않는다.

  • 참조에 의한 호출 (Call-by-Ref)

    참조에 의한 호출에서는 인자로 원본 변수의 참조(메모리 주소)가 전달된다. 이 방식은 함수 내에서 인자의 값을 변경하면 원본 변수에도 영향을 미친다.


💡 rvalue, lvalue의 차이를 설명하세요.

  • rvalue
    주로 메모리 주소를 직접 가지지 않은 임시적인 값이나 표현식을 가리킨다. rvalue는 대입 연산자의 오른쪽에 위치할 수 있으며, 일반적으로 저장되지 않고 즉시 사용되는 값이다. 예를 들어 '5', 'a+b' 와 같은 리터럴이나 표현식 결과이다.
  • lvalue
    메모리 주소가 할당된 객체를 가리킨다. lvalue는 대입 가능하며, 그 자체로 메모리 상의 위치를 나타내는 값이다. 예를 들어, 변수명, const 변수, 배열요소 등이 lvalue이다.

💡 char*, char[], string의 차이를 설명하세요.

  • char*
    문자타입 포인터로, 문자열의 시작 주소를 가리킨다. 동적으로 메모리를 할당받아 사용할 때 주로 사용하며, 'char*'는 'NULL'로 종료되는 문자열, 즉 C 스타일 문자열을 가리키는데 사용되며, 문자열을 가변적으로 다룰 수 있다.
  • char[]
    문자배열을 나타낸다. 배열의 크기는 선언시에 정해지며, 이 크기는 변경할 수 없습니다. 'char[]'도 'NULL'로 종료되는 C 스타일의 문자열을 저장하는데 사용되지만, 배열의 크기가 고정되어 있어 문자열의 길이가 변하지 않는 상황에서 주로 사용된다.
  • string
    C++ 표준 라이브러리의 일부로, 문자열을 표현하는 클래스이다. 'string'클래스는 문자열을 보다 편리하고 안전하게 다룰 수 있게 해준다. 'string'객체는 동적으로 크기가 조정될 수 있으며, 문자열 관련 다양한 함수와 연산자를 제공한다. 또한, 메모리 관리가 내부적으로 이루어지므로 메모리 누수의 위험이 줄어든다.

💡 \n과 endl의 차이를 설명하세요.

\n과 endl 모두 개행을 위해 사용되며 차이점은 endl의 경우 출력버퍼를 비워주는 과정인 flush가 들어있어 \n보다 느리다.


💡 정적 바인딩(Static Binding)과 동적 바인딩(Dynamic Binding)에 대해 설명하세요.

정적 바인딩과 동적 바인딩은 프로그래밍 언어에서 함수나 메소드 호출을 연결하는 두 가지 방법이다.

  1. 정적 바인딩
    정적 바인딩은 컴파일 시간에 함수 호출이 결정되는 과정이다. 이 방식은 컴파일러가 소스 코드를 분석하여 함수의 정의를 찾아내고, 그 함수 호출을 해당 정의에 연결합니다. 정적 바인딩은 주로 오버로딩된 함수, 템플릿 함수, 인라인 함수 등에서 사용된다. 이 방법의 장점은 실행 시간이 더 빠르다는 것이며, 컴파일 시 모든 정보가 결정되므로 더 효율적이다.
  2. 동적 바인딩
    동적 바인딩은 프로그램 실행 시간에 어떤 함수가 호출될지 결정되는 과정이다. 이는 주로 가상 함수를 통한 상속과 다형성에서 사용된다. 객체의 실제 타입을 기반으로 적절한 메소드가 실행시간에 선택된다. 예를 들어, 가상함수를 사용한 기반 클래스의 포인터나 참조를 통해 파생 클래스의 함수를 호출할 수 있다. 동적 바인딩은 유연성과 확장성을 제공하지만, 정적 바인딩에 비해 실행 시간이 더 길 수 있다.

    결론적으로, 정적 바인딩은 더 빠르고 효율적이지만 유연성이 부족하며, 동적 바인딩은 더 유연하고 확장 가능하지만 실행시간이 더 길 수 있다.


💡 캐스트 연산자에 대해 설명하세요.

캐스트 연산자는 한 데이터 타입을 다른 데이터 타입으로 변환하는 데 사용된다.

_cast <변환 type> (변환 대상)
  • static_cast
    컴파일 시간에 타입 체크를 수행하며, 관련된 타입 간 변환에 사용한다. 논리적으로 변경 가능한 경우에만 허용한다. 실수->정수, 정수->실수 변환은 가능하지만, 포인터->정수 타입 변환은 방지한다.
  • dynamic_cast
    런타임에 타입 체크를 수행하며, 주로 다운캐스팅에 사용한다. dynamic_cast를 사용하려면 Polymorphic type이어야 한다.(다형성) 포인터-포인터, 레퍼런스-레퍼런스 간의 변환만 허용한다.
  • const_cast
    객체의 상수성을 추가하거나 제거할 때 사용한다. 상수성만 변경하기 때문에, 형변환은 불가능하다.
  • reinterptet_cast
    서로 관련 없는 타입간의 변환에 사용 (임의의 포인터 타입끼리 변환을 허용하는 연산자이다.) 예를 들면 정수형에서 포인터로도 변환이 가능하다.

💡 dynamic linking, static linking의 차이를 설명하세요.

"동적 링킹과 정적 링킹은 프로그램이 외부 코드와 라이브러리를 연결하는 두 가지 방식 이다."

  • 정적 링킹
    정적 링킹은 컴파일 시간에 모든 필요한 라이브러리와 코드가 실행 가능한 파일내에 포함되어 있는 방식이다. 이 방식에는 라이브러리 코드가 프로그램의 실행 파일 안에 직접 복사된다. 결과적으로, 정적 링크된 프로그램은 라이브러리의 다른 버전이 시스템에 설치되어 있어도 영향을 받지 않으며, 외부 라이브러리에 대한 의존성 없이 독립적으로 실행할 수 있습니다. 그러나 이로 인해 실행 파일의 크기가 커질 수 있으며, 라이브러리를 업데이트할 때마다 프로그램을 다시 컴파일 해야한다.
  • 동적 링킹
    동적 링킹은 프로그램이 실행될 때 필요한 라이브러리를 연결하는 방식이다. 이 경우, 라이브러리는 별도의 파일(Ex. dll,so file)로 존재하며, 실행 시 프로그램에 로드된다. 동적 링킹을 사용하는 프로그램은 라이브러리가 시스템에 설치되어야 하며, 이 라이브러리는 프로그램이 실행될 때 메모리에 로드된다. 이 방법의 장점은 프로그램의 크기가 작아지고, 라이브러리를 업데이트할 때 프로그램을 다시 컴파일하지 않아도 된다는 것이다. 그러나 라이브러리가 시스템에 없거나 호환 되지 않는 버전이 있는경우 문제가 발생할 수 있다.

    결론적으로, 링킹 은 실행 파일의 크기가 커지지만 독립적인 실행이 가능하며, 동적 링킹은 실행 파일의 크기가 작아지고 라이브러리 업데이트가 용이하지만 외부 라이브러리에 대한 의존성이 생긴다.


💡 RAII(Resource Acquisition Is Initialization)애 대해 설명하세요.

객체가 자신의 생명주기 동안 필요한 자원(메모리, 파일핸들, 네트워크 연결)을 획득하고 해제하는 C++의 자원 관리 패턴이다. 이 패턴에서 자원의 획득은 객체의 생성과 동시에 이루어지며, 자원의 해제는 객체가 소멸될 때 자동으로 이루어진다. 예를 들어 파일을 처리하는 클래스에서 생성자에게 파일을 열고, 소멸자에서 파일을 닫는 것이 RAII 패턴의 예이다. 해당 패턴을 사용하면 예외 발생시에도 자원 누수를 방지할 수 있으며, 자원 관리를 보다 안전하고 효율적으로 할 수 있다.


💡 C++과 C의 차이점을 설명하세요.

C++ 언어는 객체지향 언어이고, C언어는 절차지향 언어이다.


💡 파이썬과 C++의 차이를 설명하세요.

파이썬과 C++ 모두 객체지향 언어이다. 파이썬은 인터프리터 언어로 소스코드를 한줄씩 읽어 명령을 처리하기 떄문에 컴파일러 언어보다 속도가 느리다. C++은 컴파일 언어이며 코드를 한번에 어셈블리 언어로 번역 후 한번에 실행하는 언어이다.


C언어 준비에 도움이 되는 사이트 https://www.guru99.com/ko/c-programming-interview-questions.html


👆 맨 위로

|

처음으로