C++ 면접 키워드

김주현·2022년 2월 22일
0
post-custom-banner

C와 C++의 차이는 무엇인가?

C언어는 절차지향 프로그래밍, C++언어는 객체지향 프로그래밍입니다.

절차지향은 순차적으로 처리하고 객체지향은 객체 중심으로 데이터와 메소드를 만들어 엮어 처리한다. 객체 지향은 캡슐화, 상속성과 같은 특징을 가지며 구조화 되어있다.

캡슐화 : 객체의 속성과 행위를 하나로 묶고, 실제 구현 내용 일부를 내부에 감추어 은닉하는것을 의미

C++에서 접근 지정자

private : 자기 클래스 내부의 메서드에서만 접근 허용
protected : 자기 클래스 내부 또는 상속받은 자식 클래스에서 접근 허용
public : 모든 접근을 허용

OOP의 5원칙 (SOLID)

S : 한 클래스는 하나의 책임만 가져야한다
O : 확장에는 열려 있으나, 변경에는 닫혀 있어야 한다.
L : 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
I : 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
D : 추상화에 의존한다. 구체화에 의존하면 안된다.

OOP의 4가지 특성

  1. 캡슐화
  • 실제로 구현 부분을 외부에 드러나지 않도록 하는 것
  • 변수와 메소드를 하나로 묶음
  • 데이터를 외부에서 직접 접근하지 않고 함수를 통해서만 접근
  • 접근 지정자
  1. 상속
  • 자식 클래스가 부모 클래스의 특성과 기능을 물려받는 것
  • 기능의 일부분을 변경하는 경우 자식 클래스에서 상속받아 수정 및 사용
  • 상속은 캡슐화를 유지, 클래스의 재사용이 용이하도록 해준다.
  1. 추상화
  • 불필요한 정보는 숨기고 중요한 정보만을 표현함으로써 프로그램을 간단히 만드는것
  1. 다형성
  • 어떤 변수,메소드가 상황에 따라 다른 결과를 내는 것

    오버로딩 : 하나의 클레스에서 메소드의 이름은 같지만, 파라메터가 다른 것
    오버라이딩 : 부모 클래스의 메소드를 자식 클래스의 용도에 맞게 재정의하여 코드의 재사용성을 높임

생성자와 소멸자는 무엇인가?

C++에서 객체를 생성하거나 제거할 때 생성자와 소멸자가 사용된다.

생성자를 이용하여 객체를 생성함과 동시에 멤버 변수를 초기화 할 수 있다.
생성자는 특별한 메소드로 클래스 이름과 동일한 이름으로 구현된다. 생성자를 따로 구현하지 않는다면 객체를 생성할 때 Default로 멤버 변수가 NULL로 초기화 된다. 또한 생성자는 입력 매개 변수를 다르게 함으로써 중복 정의할 수있다.

소멸자는 객체를 더이상 사용하지 않을 때 객체를 제거하기 위해 호출되는 함수이다. 객체의 메모리 반환을 위해 사용한다. 클래스 이름앞에 ~가 붙은 형태로 사용된다.

C++ 에서 디폴트 생성자는 무엇을 의미?

디폴트 생성자는 기본 생성자이다.

클래스에서 생성자가 없으면 객체에 접근 자체를 하지 못한다.
메모리 구조상 new연산자가 생성자를 정상적으로 실행시키면 힙영역에 객체가 생성되고, 생성된 객체의 주소가 클래스 타입 변수에 리턴되어 객체에 접근할 수 있게 되는데 생성자가 실행되지 않으면 힙 영역에 객체가 생성되지 않으니 객체의 주소도 리턴 받을 수없다.

따라서 객체를 사용하기 위해서는 반드시 생성자가 필요하고 생성자를 명시하지 않았을 때는 자동으로 기본 생성자가 선언된다.

C++ 에서 Virtual은 왜 존재하는가?

가상함수는 파생 클래스에서 재정의할 것으로 기대하는 멤버 함수를 의미한다. 즉 부모 클래스에서 선언한 함수가 자식 클래스에서 재정의할 것을 알려준다. 상속에서 오버라이딩 할 때 사용한다.

바인딩은 프로그램 요소의 성격을 결정해주는 것이다. 이 과정이 컴파일 시점에서 이뤄지면 정적바인딩 실행도중에 이뤄지면 동적바인딩이다. C++에서는 기본은 정적바인딩이다.

동적바인딩을 하기 위해 가상함수를 바꿔 선언하여 사용한다. 컴파일 시점에서 결정나기 때문에 가상함수를 사용하여 객체의 타입에 따라 멤버 함수를 선택한다. 가상 함수는 컴파일 시점에 이뤄지지 않고 보류상태로 둔다.

동적바인딩을 사용하면 어떤 포인터에 의해 접근되었는 지에 상관없이 참조된 인스턴스의 실제 클래스형에 따라 재정의된 함수 호출이 가능하다.

오버로딩과 오버라이딩

오버로딩 : 함수 중복 정의, 오버라이딩 : 함수 재정의

오버로딩은 함수명이 같은 함수를 중복 정의하는 것이다. 파라미터 개수, 파라미터의 자료형에 따라 여러개의 같은 이름의 함수를 만들 수 있다.

오버라이딩은 상속 관계에서 함수 재정의할 때 사용한다. 상속받았을 때 부모 클래스의 함수를 사용하지 않고 다른 기능을 실행할 때 함수를 자식 클래스에 같은 이름, 같은 자료형으로 재정의 해서 사용한다.

\n 과 endl의 차이점

\n과 endl 모두 출력할 때 개행을 위해 사용한다
둘의 차이는 endl은 출력 버퍼를 비워주는 과정(flush)이 들어가 있어서 \n보다 느리다.

버퍼는 입출력을 프로그램에 바로 전달하지 않고 임시 메모리 공간에 저장한 후 한번에 전송하는 역할을 한다. 버퍼를 즉시 비우고 싶다면 endl을 그렇지 않다면 \n을 사용한다.

malloc 과 new의 차이는 무엇인가?

A) malloc과 new 모두 동적할당을 하기 위해 사용된다.

보통 malloc은 C언어에서 new는 C++언어에서 사용된다.

malloc은 함수고 new는 연산자이다.
malloc은 heap 영역에서, new는 dynamic memory에서 할당된다.

malloc는 초기값 지정 불가능하고, new는 초기값 지정이 가능하다. new는 객체에서 생성자를 자동으로 호출하고 초기화 해준다.

객체의 경우에는 new를 사용하는 것이 맞지만, 재할당이 많이 일어날 경우에는 malloc으로 동적할당하는 경우도 있다. relloc과 같은 함수의 존재 때문에 malloc을 이용하는 경우도 있다.

struct와 class의 차이는 무엇인가?

C++에서 struct와 class는 객체를 구조화 역할을 한다.
struct에서는 기본 한정자가 public이고, class에서는 private이다.

구조체와 class 모두 상속이 가능하고 함수를 추가할 수도 있다.

얕은 복사와 깊은 복사

객체를 생성하고 초기화실킬 때 멤버변수를 어떻게 초기화느냐에 따라 얕은 복사, 깊은 복사를 나눈다.

얕은 복사는 실제 데이터가 아닌 단지 메모리 주소만을 복사한다.

깊은 복사는 변수가 관리하는 리소스 자체를 복사(새롭게 메모리를 할당)하여 새롭게 멤버 변수에 복사한다. 얕은 복사에 비해 작업 시간과 리소스의 소모가 따른다.

입출력 실행속도 높이는 방법

C++에서 printf와 scanf보다 cin,cout은 속도가 현저히 떨어진다. 그럴때 다음 코드를 추가해서 입출력 실행속도를 줄일 수 있다.

ios::sync_with_stdio(false);
다음은 C++의 iostream을 C의 stdio와 동기화를 끄게 된다. iostream과 stdio의 버퍼를 모두 사용하므로 딜레이가 발생되는데 이를 끊어 실행 속도를 높아지게 한다.

하지만 이는 printf,scanf와 함께 사용하면 안되고, 싱글 쓰레드 환경에서만 사용이 가능하다.

C++ 프로그램 빌드 과정

전처리-컴파일러-어셈블러-링커

컴퓨터는 0과 1로만 이루어져있기 때문에 컴퓨터가 이해할 수 있도록 만들어 주어야 한다. 이런 과정을 빌드라고 한다.

전처리(Preprocessing) : 코드의 주석을 제거, 전처리 지시문을 수행
컴파일러 : 어셈블리 파일로 변환한다. 어셈블리(저수준 언어)는 CPU 명령어 조합이다(어휘 분석,구문 분석,의미 분석)
어셈블러 : 오브젝트 파일로 변환한다. 오브젝트 코드는 0과 1로 이루어진 코드를 말한다.
링커 : 오브젝트 파일들을 묶어서 실행 코드 파일로 변환한다. 운영체제가 로딩할 수 있도록 주소 정보를 할당한 파일을 만들어 낸다. 번역된 파일을 하나로 연결해 실행가능한 파일로 만들어준다.

컴파일 언어의 장점
빌드가 완료된 실행가능한 파일은 실행 속도가 빠르다.

디버그와 릴리즈 모드 차이

디버그 모드
-실행파일에 디버깅 정보를 포함
-실행파일 상태 정보 확인 가능
-디버깅 정보를 포함하였기 때문에 속도가 릴리즈모드에 비해 느리다

릴리즈 모드
-코드를 최적화하여 실행파일의 크기를 최대한 줄인다.
-속도가 디버그 모드에 비해 빠르고, 파일의 크기가 비교적 작다. 메모리 점유율이 낮음
-초기화가 이루어지지 않는다.

객체지향 디자인

절차 vs 객체
절차지향은 순차적으로 처리하고 객체지향은 객체 중심으로 데이터와 메소드를 만들어 엮어 처리한다. 객체 지향은 캡슐화, 상속성과 같은 특징을 가지며 구조화 되어있다.

클래스와 객체의 차이

클래스 : 객체를 만들기 위한 설계도, 해당 설계도를 통해 만들어진 무언가 이를 객체 또 다른 표현으로 인스턴스라 한다.

객체란 : 물리적으로 존재하거나 추상적으로 생각할 수 있는 것중에서 자신의 속성을 가지고 있고 다른것과 식별 가능한 것.

is-A Has-A

is-a는 말 그대로 'A는 B이다'일 때의 '~이다'와 같습니다.

is-a는 추상화들 사이의 포함 관계를 의미하며, 한 클래스 A가 다른 클래스 B의 서브클래스(파생클래스)임을 이야기 합니다. 다른 말로, 타입 A는 타입 B의 명세를 암시하는 점에서 타입 B의 서브타입이라고도 할 수 있음

has-a는 구성 관계를 의미하며 한 오브젝트가 다른 오브젝트에 속한다를 말합니다. 단순히 말해, has-a 관계는 객체의 멤버 필드라고 불리는 객체를 말하며, Multiple has-a 관계는 소유 계층구조를 형성하기 위해 결합하는 경우를 말합니다

상속은 is 관계가 확실할 때

구성의 경우, 하나의 객체가 다른 객체를 갖거나 하는 경우에 사용 가능

다중 상속의 장단점

다중상속을 허용하면 여러 클래스로부터 상속받을 수 있기 때문에 복합적인 기능을 가진 클래스를 쉽게 작성할 수 있다는 장점이 있지만, 클래스간의 관계가 매우 복잡해진다는 것과 서로 다른 클래스로부터 상속받은 멤버간의 이름이 같은 경우 구별할 수 있는 방법이 없다는 단점이 있다.

단일 상속이 하나의 조상 클래스만을 가질 수 있기 때문에 다중상속에 비해 불편한 점도 있겠지만, 클래스 간의 관계가 보다 명확해지고 코드를 더욱 신뢰할 수 있게 만들어 준다는 점에서 다중상속보다 유리하다.

추상화 원칙

추상화란 어떠한 기능 중 핵심적인 기능을 추출하여 이를 일반화하는 객체 지향 설계 원칙이다. 여러 개의 객체에서 공통적이고 핵심적인 기능을 추출하고 문제 영역, 관점에 따라 필요하지 않은 기능을 제거해 대상화하는 객체 지향 설계 원칙이다.

주로 인터페이스나 추상 클래스로 구현한다.

추상화의 특징으로는 문제 영역이나 관점에 의존적이라는 점이며, 이로 인해 같은 대상이라고 하더라도 어떠한 문제 영역, 관점에서 추상화를 진행했느냐에 따라 여러 가지의 추상화 모델이 나올 수 있다는 점이다.

추상화를 진행함으로써 얻을 수 있는 장점은

  • 복잡도를 관리할 수있다.
  • 유연한 설계가 가능하다.
  • 코드를 간결하게 해준다.

엔디안

엔디언은 컴퓨터의 메모리와 같은 1차원의 공간에 여러 개의 연속된 대상을 배열하는 방법을 뜻하며, 바이트를 배열하는 방법을 특히 바이트 순서라한다.

빅 엔디안은 최상위 바이트부터 차례로 저장하는 방식
리틀 엔디안은 최하위 바이트부터 차례로 저장하는 방식

빅 엔디안은 소프트웨어의 디버그를 편하게 해주는 경향이 있음
리틀 엔디안은 메모리에 저장된 값의 하위 바이트들만 사용할 때 별도의 게산이 필요 없다.

빅을 통한 숫자 비교시, 숫자의 비교는 가장 큰 값이 들어가는 왼쪽부터 하게 되는데, 빅 엔디언은 비교가빠르고 리틀 엔디안은 계산 연산이 빠르다.

메모리 관리

메모리 구조

프로그램이 실행되기 위해서는 먼저 프로그램이 메몰에 로드되어야 합니다.

또한,프로그램에서 사용되는 변수들을 저장할 메모리도 필요합니다.

따라서 컴퓨터의 운영체제는 프로그램의 실행을 위해 다양한 메모리 공간을 제공

프로그램이 운영체제로부터 할당받는 대표적인 메모리 공간은 4가지

코드,데이터,힙,스택

  1. 코드

메모리의 코드 영역은 실행할 프로그램의 코드가 저장되는 영역으로 텍스트 영역이라고도 부름
CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리

  1. 데이터 영역

메모리의 데이터 영역은 프로그램의 전역 변수와 정적 변수가 저장되는 영역입니다.
데이터 영역은 프로그램의 시작과 함께 할당되며, 프로그램이 종료되면 소멸합니다.

  1. 스택 영역

메모리의 스택 영역은 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역입니다.

스탱 영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸합니다.
이렇게 스택 영역에 저장되는 함수의 호출 정보를 스택 프레임이라고 합니다.

스택 영역은 푸시동작으로 데이터를 저장하고, 팝 동작으로 데이터를 인출합니다.
이러한 스택 후입선출(LIFO,Last_In First_Out) 방식에 따라 동작하므로, 가장 늦게 저장된 데이터가 가장 먼저 인출됩니다.

스택 영역은 메모리의 높은 주소에서 낮은 주소의 방향으로 할당됩니다.

컴파일 타임에 크기가 결정됩니다.

  1. 힙 영역

메모리의 힙 영역은 사용자가 직접 관리할 수 있는 '그리고 해야만 하는'메모리 영역입니다.

힙 영역은 사용자에 의해 메모리 공간이 동적으로 할당되고 해제됩니다.

힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당됩니다.

스택과 힙의 장단점

  • 스택

매우 빠른 액세스
변수를 명시적으로 할당 해제 할 필요가 없습니다.
공간은 CPU에 의해 효율적으로 관리되고 메모리는 단편화되지 않습니다.
지역 변수만
스택 크기 제한
변수의 크기 조정 불가

변수는 전역적으로 액세스 가능
메모리 크기 제한 없음
상대적으로 느린 액세스
효율적인 공간 사용을 보장하지 못하면 메모리 블록이 할당 된 후 시간이 지남에 따라 메모리가 조각화되어 해제 될 수 있습니다.
메모리를 관리해야합니다(변수를 할당하고 해제하는 책임이 있습니다)

스마트 포인터

C++ 프로그램에서 new 키워드를 사용하여 동적으로 할당받은 메모리는, 반드시 delete 키워드를 사용하여 해제해야 합니다. C++에서는 메모리 누수로부터 프로그램의 안전성을 보장하기 위해 스마트 포인터를 제공하고 있습니다. 스마트 포인터란 포인터처럼 동작하는 클래스 템플릿으로, 사용이 끝난 메모리를 자동으로 해제해 줍니다.

스마트 포인터의 동작
보통 new 키워드를 사용해 기본 포인터가 실제 메모리를 가리키도록 초기화한 후에, 기본 포인터를 스마트 포인터에 대입하여 사용합니다.
이렇게 정의된 스마트 포인터의 수명이 다하면, 소멸자가 delete 키워드를 사용하여 할당된 메모리를 자동으로 해제합니다.
따라서 new 키워드가 반환하는 주소값을 스마트 포인터에 대입하면, 따로 메모리를 해제할 필요가 없어집니다.

unique_ptr

unique_ptr은 하나의 스마트 포인터만이 특정 객체를 소유할 수 있도록, 객체에 소유권 개념을 도입한 스마트 포인터입니다.

이 스마트 포인터는 해당 객체의 소유권을 가지고 있을 때만, 소멸자가 해당 객체를 삭제할 수 있습니다.
unique_ptr인스턴스는 move() 멤버 함수를 통해 소유권을 이전할 수는 있지만 복사할 수는 없습니다.
소유권이 이전되면, 이전 unizue_ptr 인스턴스는 더는 해당 객체를 소유하지 않게 재설정 됩니다.

unique_ptr<int> ptr01(new int(5)); //int 형 unique_ptr인 ptr01을 선언하고 초기화함
auto ptr02 = move(ptr01); // ptr01 에서 ptr02fh 소유권을 이전함
//unique_ptr<int> ptr03 = ptr01 // 대입 연산자를 이용한 복사는 오류를 발생시킴
ptr02.reset(); //ptr02가 가리키고 있는 메모리 영역 삭제

c++14 이후부터 제공되는 make_unique()함수를 사용하면 unique_ptr인스턴스를 안전하게 생성할 수 있습니다.

make_unique() 함수는 전달받은 인수를 사용해 지정된 타입의 객체를 생성하고, 생성된 객체를 가리키는 unique_ptr을 반환합니다. 이 함수를 사용하면,예외 발생에 대해 안전하게 대처할 수 있습니다.

unique_ptr \ hong = make_unique \ ("길동",29);

shared_ptr

shared_ptr은 하나의 특정 객체를 참조하는 스마트 포인터가 총 몇 개인지를 참조하는 스마트 포인터입니다. 이렇게 참조하고 있는 스마트 포인터의 개수를 참조 횟수라고 합니다. 참조 횟수는 특정 객체에 새로운 shared_ptr이 추가될 때마다 1씩 증가하며, 수명이 다할 때마다 1씩 감소합니다.
따라서 마지막 shared_ptr의 수명이 다하여 참조 횟수가 0이되면 delete 키워드를 사용하여 메모리를 자동으로 해제합니다.

shared_ptr<int> ptr01(new int(5)); // int형 shared_ptr인 ptr01을 선언하고 초기화함

cout << ptr01.use_count() << endl; // 1
auto ptr02(ptr01); //복사 생성자를 이용한 초기화
cout << ptr01.use_count() << endl; // 2
auto ptr03 = ptr01; // 대입을 통한 초기화
cout << ptr01.use_count() << endl // 3

위의 예제에서 사용된 use_count() 멤버 함수는 shared_ptr 객체가 현재 가리키고 있는 리소스를 참조 중인 소유자의 수를 반환해 줍니다.

위와 같은 방법 이외에도 make_shared() 함수를 사용하면 shared_ptr인스턴스를 안전하게 생성 가능. make_shared() 함수는 전달받은 인수를 사용해 지정된 타입의 객체를 생성하고, 생성된 객체를 가리키는 shared_ptr을 반환합니다. 이 함수를 사용하면, 예외 발생에 대해 안전하게 대저할 수 있습니다.

다음 예제는 Person 객체를 가리키는 hong이라는 shared_ptr을 make_shared() 함수를 통해 생성하는 예제입니다.

shared_ptr<Person> hong = make_shared<Person>("길동", 29);

cout << "현재 소유자 수 : " << hong.use_count() << endl; // 1

auto han = hong;

cout << "현재 소유자 수 : " << hong.use_count() << endl; // 2

han.reset(); // shared_ptr인 han을 해제함.

cout << "현재 소유자 수 : " << hong.use_count() << endl; // 1

weak_ptr

weak_ptr은 하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대한 접근을 제공하지만, 소유자의 수에는 포함되지 않는 스마트 포인터 입니다.

shared_ptr은 참조 횟수를 기반으로 동작하는 스마트 포인터입니다.
만약 서로가 상대방을 가리키는 shared_ptr를 가지고 있다면, 참조 횟수는 절대 0이 되지 않으므로 메모리는 영원히 해제되지 않습니다. 이렇게 서로가 상대방을 참조하고 있는 상황을 순환 참조라고 합니다. weak_ptr은 바로 이러한 shared_ptr 인스턴스 사이의 순환 참조를 제거하기 위해서 사용됩니다.

소멸자의 virtual 키워드

왜 다형성을 가진 C++클래스의 소멸자에는 virtual 키워드를 붙일까?
(다형성을 가지지 않는다면 별로 상관없다.virtual 자체가 상속과 다형성에 관련된 키워드 이므로)

다형성를 가진 행동을 하기 위해서 상속 관계 안에서 각각의 객체를 구분하기 위해 함수에 virtual 키워드를 붙인 것 처럼
소멸자도 역시 상속 관계 안에서 정말 자신의 객체를 소멸시키기 위하여 소멸자에 virtual 키워드를 붙인다.

잊지말자
다형성을 가진 상속관계에서는 반드시 소멸자에 virtual 키워드를 붙여야 한다는 것

new() 와 malloc()의 차이

아주 단순 한 비교로는 malloc()은 함수이고 new는 연산자이다.
그리고 발생하는 가장 큰 차이는 생성자의 유무입니다. malloc()은 시스템 함수로서 함수 안에서 메모리를 할당하지만 new는 연산자로 바로 메모리를 할당하는게 아니라 생성자를 호출하여 메모리를 할당합니다. 그러므로 생성자를 통하여 호출하기 때문에 new로 메모리를 할당하면 생성 시 초기화가 가능한 장점이 있습니다.

relloc()의 대표적 문제는 정말 혹시나 메모리 할당이 실패할 경우 null이 반환되기 때문에 기존의 메모리가 할당되어 있는 포인터를 잃어버리는 것이다.

그래서 realloc()을 할 때는 기존의 메모리 주소를 저장하고 실패 시 복구하는 프로세스가 함께 있어야 한다.

생성 후 초기화는 객체를 생성한 후 대입을 통한 초기화
생성 시 초기화는 이니셜라이즈 리스트를 통한 초기화

버블 정렬

void Bubble_Sort(int a[], int len)
{
     for(int i = len - 1; i > 0; i--)
          for (int j = 0; j < i; j++)
               if (a[j] > a[j+1])
               {
                    int t = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = t;
               }
}

삽입 정렬


#include <vector>

template <typename T>
void insertionSort(std::vector<T>& vec, const int& left, const int& right){
  for (int i = left; i < right; ++i){
    for (int j = i + 1; j > left && vec[j] < vec[j - 1]; --j){
      std::swap(vec[j], vec[j - 1]);
    }
  }
}

선택 정렬

  // 선택 정렬
void selection_sort(int list[], int n){
  int i, j, least, temp;

  // 마지막 숫자는 자동으로 정렬되기 때문에 (숫자 개수-1) 만큼 반복한다.
  for(i=0; i<n-1; i++){
    least = i;

    // 최솟값을 탐색한다.
    for(j=i+1; j<n; j++){
      if(list[j]<list[least])
        least = j;
    }

    // 최솟값이 자기 자신이면 자료 이동을 하지 않는다.
    if(i != least){
        SWAP(list[i], list[least], temp);
    }
  }
}

퀵정렬

#include <iostream>
using namespace std;
//퀵정렬
int n,cnt, quick[10000001];

void quickSort(int i, int j)
{
	if(i>=j) return;
	int pivot = quick[(i+j)/2];
	int left = i;
	int right = j;
	
	while(left<=right)
	{
		while(quick[left]<pivot) left++;
		while(quick[right]>pivot) right--;
		if(left<=right)
		{
			swap(quick[left],quick[right]);
			left++; right--;
		}
	}
	quickSort(i,right);
	quickSort(left,j);
}

OSI 7계층

7계층 – 응용 계층(Application)

6계층 – 표현 계층(Presentation)

5계층 – 세션 계층(Session)

4계층 – 전송 계층(Transport)

3계층 – 네트워크 계층(Network)

2계층 – 데이터 링크 계층(Data Link)

1계층 – 물리 계층(Physical)

TCP vs UDP

TCP / UDP 란?
: 전송계층에서 사용하는 프로토콜로써, 목적지 장비까지 전송한 패킷을 상위의 특정 응용 프로토콜에게 전달하는 것에 목적이 있습니다. 전송방식으로는 TCP와 UDP가 있습니다.

전송계층이란? 송신자와 수신자를 연결하는 통신 서비스를 제공하는 계층으로, 쉽게 말해 데이터의 전달을 담당합니다.

TCP란? (Transmission control protocol)
: 연결형 서비스를 지원하는 전송 계층 프로토콜로써,인터넷 환경에서 기본으로 사용합니다. 호스트간 신뢰성 있는 데이터 전달과 흐름제어를 합니다. 즉, 인터넷상에서 데이터를 메시지의 형태로 보내기 위해 IP와 함께 사용하는 프로토콜 입니다. 일반적으로 TCP와 IP를 함께 사용하는데, IP가 데이터의 배달을 처리한다면 TCP는 패킷을 추적 및 관리하게 됩니다.

TCP 특징
1.연결형 서비스로 가상 회선 방식을 제공.
2.데이터의 경계를 구분하지 않는다.
3.데이터의 전송 순서 보장한다.
4.UDP보다 전송속도가 느리다.
5.신뢰성있는 데이터를 전송한다.

UDP란? (User Datagram Protocol)
:비연결형 서비스를 지원하는 전송계층 프로토콜로써, 인터넷상에서 서로 정보를 주고받을 때 정보를 보낸다는 신호나 받는다는 신호 절차를 거치지 않고,보내는 쪽에서 일방적으로 데이터를 전달하는 통신 프로토콜 입니다.
데이터를 데이터 그램(독립적인 관계를 지니는 패킷) 단위로 처리하는 프로토콜입니다.

UDP 특징
1. 비연결형 서비스로 데이터그램 방식을 제공
2. 정보를 주고 받을때 정보를 보내거나 받는다는 신호를 거치지 않는다.
3. 신뢰성 없는 데이터를 전송한다.
4. 데이터의 경계를 구분한다.
5. TCP보다 전송속도가 빠르다.

결론(차이점)
:TCP는 연속성보다 신뢰성있는 전송이 중요할 떄에 사용하는 프로토콜이며.
UDP는 TCP보다 속도가 빠르며 네트워크 부하가 적다는 장점이 있지만, 신뢰성있는 데이터 전송을 보장하지는 않습니다.
그렇기 때문에 신뢰성보다는 연속성이 중요한 서비스의 예를 들면 실시간 서비스에 자주 사용됩니다.

다익스트라

vector<int> dijkstra(int start, int V, vector<pair<int,int> > adj[]) {
    vector<int> dist(V, INF);    // 전부 INF로 초기화 
    priority_queue<pair<int, int> > pq;
    
    dist[start] = 0;
    pq.push(make_pair(0, start));    // 시작 정점 방문 
 
    while (!pq.empty()) {
        int cost = -pq.top().first;    // 방문한 정점의 dist 값 
        int cur = pq.top().second;    // 현재 방문한 정점 
        pq.pop();
 
        for (int i = 0; i < adj[cur].size(); i++) {    // 현재 방문한 정점의 주변 정점 모두 조사 
            int next = adj[cur][i].first;    // 조사할 다음 정점 
            int nCost = cost + adj[cur][i].second;    // 현재 방문한 정점을 거쳐서 다음 정점을 갈때의 비용 
            if (nCost < dist[next] ) {     // 기존 비용보다 현재 방문한 정점을 거친 비용이 더 싸다면 
                dist[next] = nCost;    // 갱신 
                pq.push(make_pair(-nCost, next));    // pq에 저장 
            }
        }
    }
    
    return dist;
}

에이스타 알고리즘

https://namu.wiki/w/A*%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98

함수 오버로딩에 대해여 설명하여라

C++에서 함수호출 시 전달되는 인자를 통해서 호출하고자 하는 함수의 구분이 가능하기 때문에 매개변수가 다른 동일한 이름의 함수를 허용한다.

매개변수의 개수와,자료혀이 다른 같은 이름의 함수를 중복 정의 하는 것.

객체지향 언어 vs 절차지향언어

절차지향언어 : 순차적 실행, 컴퓨터의 작업처리방식과 유사하여 객체 지향보다 빠른 처리 기능,계산 중심언어, 함수가 중심이 되고, 데이터는 보조기능

객체지향언어 : 실제 세계를 모델링 또한 추상화,캡슐화,상속,다형성의 특징

-추상화 : 불필요 정보는 숨기고 중요 정보만을 표현
-캡슐화 : 코드 재활용 목적,캡슐화를 지켜야 상속과 다형성이 성립
-상속 : 하나의 클래스가 가지고 있는 특징을 그대로 다른 클래스에게 물려줌
-다형성 : 하나의 변수에 여러 종류 데이터를 대입 할 수 있는 성질

변수와 메모리에 대해서

프로그램을 실행시키면 운영체제는 우리가 실행시킨 프로그램을 위해 메모리 공간을 할당 해준다. 메모리 공간은 코드,데이터,힙,스택 영역으로 나누어진다.

데이터 영역 -> 전역변수와 정적변수가 할당되는 영역, 프로그램 시작과 동시 할당되고 프로그램이 종료 되어야 메모리에서 소멸

스택 영역 -> 함수 호출시 생성되는 지역변수와 매개변수가 저장되는 영역, 함수 호출시 사라짐

힙 영역 -> 필요에 의헤 동적으로 메모리를 할당 할 때 사용,할당해야 할 메모리의 크기를 프로그램이 실행 동안 결정해야 하는 경우 유용하게 사용되는 공간이다.

Call by Value 와 Call by Referenece에 대해 설명하라

콜 바이 밸류 : 어떤 함수를 호출할때에 전달인자로 그 데이터 값 자체를 전달하는 호출 방법이다.

콜 바이 레퍼런스 : 어떤 특정한 데이터 값이 아닌 그 값에 대한 정보를 전달하는 호출방법이다. 주소(값에 대한 정보)를 매개 변수로 전달하여 swap시 실제 값이 변경 된다.

깊은 복사와 얕은 복사에 대해서 설명하라

디폴트 복사 생성자는 멤버 대 멤버를 단순히 복사만 하므로,문제가 된다.
포인터 멤버 변수의 경우 복사 생성된 객체의 변수의 포인터 또한 동일하기 때문.
이는 하나의 변수를 두 개의 객체가 참조하는 꼴을 만든다.
이후에 객체를 소멸할 때 문제가 발생 한다.
따라서 깊은 복사의 코드로 복사생성자를 구현을 해주어야 한다.

오버리이딩에 대해서 설명하여라.

오버라이딩이란 상위 클래스에 있는 메서드와 똑같은 메서드를 하위 클레스에서 재정의 하는 것을 말한다.

연산자 오버로딩

연산자 오버로딩의 경우 멤버함수가 우선시 되어 호출.

Static

전역 변수에 선언된 static의 의미
:선언된 파일 내에서만 참조를 허용하겠다는 의미

함수 내에 선언된 static의 의미
: 한번만 초기화되고,지역변수와 달리 함수를 빠져나가도 소멸되지 않는다.

static 멤버 변수
: 클래스 변수라고도 한다. 메모리 공간에 딱 하나만 할당이 되어서 공유되는 변수. 멤버 변수 접근하듯 접근은 할 수있지만, 객체 내에 존재하는 것이 아니라, 객체 외부에 있는 변수이다. 다만 객체에게 멤버변수처럼 접근 할 수 있는 권한을 줬을 뿐
ClassName::Val->와 같이도 접근 할 수 있다.

static 멤버 함수
: 선언된 클래스의 모든 객체가 공유,public 선언시 이름을 통해 호출가능, 객체의 멤버로 존재 하는 것이 아니다.

주의 할 것. 객체의 멤버가 아니기 때문에 함수 내에서 일반 멤버 변수의 값에 접근 하면 안됨
객체생성 이전에도 호출이 가능하기 때문에 static 멤버 변수만 접근 가능.

가상 함수

C++ 컴파일러가 실제로 가리키는 객체의 자료형을 기준으로 하는게 아닌, 포인터 변수의 자료형을 기준으로 판단하기 때문에 실제로 가리키는 객체의 자료형에 따라 멤버 함수가 호출 되도록 해주는 장치

한 개 이상의 가상함수를 포함하는 클래스에 대해서는 컴파일러가 가상 함수 테이블을 만든다.
가상함수 테이블을 key와 value로 구성 되어있다.
key와 value key는 호출하고자 하는 함수,value는 주소정보를 알려주는 정보이다.
무조건 가장 마지막에 오버라이딩을 한 자식 클래스의 멤버함수가 테이블에 포함 된다.

클래스에 가상 함수가 포함되면 가상함수 테이블이 생성되고, 이 테이블을 참조하 때문에 실행 속도가 감소 한다.

순수 가상 함수

함수의 선언만 있고 정의는 없는 것으로, 자식 클래스에서 바드시 재정의 해주어야 하고 뒷 부분에 =0을 덧붙여 인스턴싱 할 수 없도록 만드는 장치. 순수 가상 함수를 포함하는 클래스를 추상 클래스 라고 한다.

가상 소멸자

상속을 받은 클래스의 생성과 소멸 과정을 보자. 생성자는 부모 클래스의 생성자가 먼저 불려지고, 소멸자는 자식 클래스의 소멸자가 먼저 불려지고 나서 부모 클래스의 소멸자가 불려진다. 근데 다형성 이용을 위해 부모 클래스의 포인터로부터 자식 클래스를 호출할 때, 가상 함수로 정의되지 않은 자식 클래스의 오버라이딩된 함수를 호출하면 부모 클래스의 멤버 함수가 호출된다. 소멸자도 자식 클래스에서 오버라이딩된 함수라고 볼 수 있기 때문에 만약 부모 포인터로 객체를 삭제하면 부모 클래스의 소멸자가 호출된다.

따라서 소멸자를 가상 함수로 선언하지 않으면 이 경우 자식 클래스의 소멸자는 결코 호출되지 않는다. 가상 함수 키워드 virtual이 사용되었다면 이것은 자식 클래스에서 재정의될 수 있음을 명시하기 때문에 포인터의 종류에 상관없이 항상 자식 클래스의 메서드가 호출된다. 즉 자식 클래스의 소멸자가 호출되고 나서 부모 클래스의 소멸자가 호출된다.

따라서 상속 관계가 있고 소멸자에서 리소스를 해제해야 하는 경우 반드시 소멸자를 가상 함수로 선언해야 한다.

대입 연산자

복사생성자와 마찬가지로 동적 할당으로 인해 깊은 복사가 필요할 때 프로그래머가 구현
이미 생성 및 초기화가 진행된 객체를 대상으로 operator=를 호출하여 대입 하는 경우를 말함

자식클래스의 대입연산자를 정의해야 하는 상황에 놓이게 되면, 부모 클래스의 대입연산자를 명시적으로 호출해야 한다.

명시적으로 기초 클래스의 대입 연산자 호출문을 삽입하지 않으면 기초 클래스의 대입 연산자는 호출되지 않아서 기초 클래스의 멤버변수는 복사 대상에서 제외된다.

형 변환 연산자

dynamic_cast는 다음과 같은 상황에만 형 변환이 가능하다.

"상속 관계에 놓여 있는 두 클래스 사이에서 유도 클래스의 포인터 및 참조형 데이터를 기초 클래스의 포인터 및 참조형 데이터로 형 변환하는 경우"

static_cast

static_cast는 dynamic_cast와 다르게 유도 클래스의 포인터 및 참조형 데이터를 기초 클래스의 포인터 및 참조형 데이터로 뿐만 아니라, 기초 클래스의 포인터 및 참조형 데이터도 유도 클래스의 포인터 및 참조형 데이터로 아무런 조건 없이 형 변환시켜주지만, 그에 대한 책임은 프로그래머가 져야 한다.

const_cast
:const를 제거 하는 용도로 쓰인다.

reinterpret_cast
:C스타일의 캐스팅과 가장 비슷한 기능을 한다.

싱글톤 패턴
:
하나의 인스턴스만을 생성하고 사용 할 수 있다.

생성자를 private으로 두고. 자기 자신을 얻는 함수를 만들어 미리 만들어 두었던 자기 자신 객체를 반환 하는 방법으로 사용.

프로그램 내에 단 하나만 존재해야 하는 객체가 필요 할 때 사용

단점 : 객체가 static으로 선언되기 때문에 싱글톤 객체를 사용하지 않더라도 일단 메모리에 올려두기에 메모리 낭비가 될 수있다.

제네릭 프로그래밍이란 무엇인가?

데이터 형식에 의존하지 않고, 하나의 갓이 여러 다른 데이터 타입들을 가질 수 있는 기술에 중점을 두어 재사용을 높일 수 있는 프로그래밍 방식으로 템플릿은 STL 제네릭 프로그래밍의 핵심이다.

함수객체

함수호출연산자를 오버로딩 하여 객체가 함수처럼 동작하도록 구현 한것
함수와 달리 객체를 사용하면서 속성을 지닐 수 있는 것이 가능하고, 함수 객체가 일반적인 함수보다 빠르기도 하고 각각의 함수 객체는 서로 다른 타입을 지닌다는 장점을 가진다.

C와 C++의 차이점

C는 절차지향 C++은 객체지향
C++는 C와는 달리 같은 이름을 가진 함수가 존재 가능(오버로딩, 오버 라이딩)
C언어에서는 변수,함수를 초기에 작성해야하지만, C++에서는 중간에 어디서든 선언 가능

클래스와 구조체의 차이점

구조체는 하나의 구조로 묶일수 있는 데이터, 즉 변수들의 집합
클래스는 변수 뿐만 아니라 함수(메서드)까지 포함시킬 수 있다는 점
하지만 C에서도 함수포인터를 이용해 구조체를 클래스화 시킬 수 있다.

구조체는 상속이 안됨. 클래스는 상속이 됨.
구조체의 =연산자로 인한 객체생성은 멤버 초깃값들이 값복사가 일어나나
클래스의 =연산자로 인한 객체생성은 멤버 초깃값들이 참조복사가 일어나요.
구조체는 멤버 초기화하는데 있어서 까다롭기 때문에 그 규칙을 좀 익혀야 하나
클래스는 그냥 평소 아시는대로 하면 돼요.

구조체는 매개변수가 없는 생성자가 이미 가지고 있기 때문에
생성자를 굳이 만드시고 싶으면 반드시 매개변수가 있는 생성자를 만들어야 하며
매개변수가 있는 생성자를 만들때는 무조건 가지고 있는 모든 변수를 초기화해야 함.
초기화 할 때는 멤버 변수 선언과 동시에 =연산자로 직접 초기화할수 없고
함수 안에서 초기화 시켜야 해요.

OOP

절차지향 : 해야할 작업을 순서대로 코딩한다. 함수 단위로 구성되며 기능별로 묶어둠

객체지향 : 주 구성요소는 클래스와 객체이다. 그리고 상속과 다형셩을 특징으로 들 수 있다. 클래스를 활용하여 각각의 기능별로 구성이 가능하며, 이를 나중에 하나로 합쳐서 프로그램의 완성이 가능하다. 객체 별로 개발이 가능하기에 팀 프로젝트를 하기에도 유리한 장점을 가지고 있다. 또한 코드의 재사용이 가능하며, 오류 발생 가능성이 적고 안정성이 높다.

스크립트언어와 컴파일 언어 차이점

스크립트 : 자바스크립트, 파이썬
컴파일 : C,C++

차이점 : 컴파일러의 존재 여부

컴파일 언어의 경우 컴파일러를 통해서 한번 컴파일 된 후에는 코드 수정 후 재 컴파일을 하기 전까지는 같은 결과를 나타내지만, 스크립트 언어의 경우 실행될 떄 바로 해석하므로 코드 변경시 실행 할 떄마다 결과가 바뀌게 된다.

프로세스와 스레드의 차이

프로세스 : 실행중인 프로그램을 나타낸다. 이는 CPU가 실행되고 있는 프로세스에 대해서 메모리 자원을 안정되게 분배해줘야 하며 이는 운영체제의 성능에 따라 결정된다.

스레드 : 하나의 프로세스 내에서 할당 받은 자원을 공유하며 실행되는 독립적인 작업단위이다. 즉, 스레드는 각자의 스택 메모리영역을 가지고 있으며 동일한 프로세스 내의 다른 스레드들과 전역 메모리를 공유한다. 따라서 CPU로부터 새로운 자원을 할당받지 않아도 되기 때문에 프로세스보다 실행 속도가 빠르다는 장점을 가지고 있다.

스레드 생성 방법과 스레드의 장/단점

장점 : 빠른 프로세스 생성, 적은 메모리 사용, 쉬운 정보 공유
단점 : 교착 상태

동기화란 무엇이며 어떠한 경우에 사용하는가?

다중 스레드에서 하나의 자료에 접근할 때 사용한다 (static으로 선언되어 있거나 배열에 접근하는 경우)
예를 들면, 은행계좌에 있는 돈에 대하여 동시에 출금 요청(접근)이 가능하다면 한 쪽에서 출금 처리가 완료되기 전에 다른 쪽에서 출금을 요청하면 출금이 될 수 있기 때문에 반드시 동기화 처리를 해서 작업이 일어나는 중에는 다른 쪽에서의 접근을 막아주어야 한다.

포인터의 개념에 대해 설명하고 이해할 수 있도록 풀어서 설명

포인터란 메모리 주소를 저장하는 변수이다.

예를 들면 주소를 지칭하고 있는 곳이다. 엘리베이터에서 포인터는 해당 층을 표시하는 버튼 이며, 10층 버튼을 누르면 10층으로 이동하듯이 해당 위치를 가리키고 있는 변수이다.

포인터를 사용할 때 주의할 점은 어떠한 주소를 가리키고 있어야 사용이 가능하다.

오버로딩과 오버라이딩의 차이

오버로딩 : 같은 이름의 메서드를 여러개 정의하는 것. 단, 매개변수의 타입이 다르거나,갯수가 달라야한다. 리턴 타입이나 접근 제어자는 영향을 주지 않는다.

오버라이딩 : 상속에서 나온 개념. 클래스를 메서드의 하위 클래스에서 재정의 하는 것을 의미한다.

추상클래스에 대해 설명하시오

  • 추상 메서드를 하나 이상 가진 클래스이다.
  • 자신의 생성자로 객체 생성이 불가능하다. 그 이유는 몸체도 정의되어 있지 않은 추상 클래스의 객체를 만든다는 것은 아무런 의미가 없기 때문. 하지만 추상 클래스의 포인터는 선언이 가능하다.
  • 순수 가상 함수가 하나라도 선언되어있다면 그 클래스는 추상 클래스
  • 하위 클래스를 참조하여 상위 클래스의 객체를 생성

다형성에 대해 설명하시오

서로 다른 객체가 동일한 메시지에 대하여 서로 다른 방법으로 응답할 수 있는 기능. 즉, 같은 메서드 호출에 대해 서로 다른 방법으로 응답을 하게 되는것(상속에서 효과를 발휘)

가상함수와 순수가상함수의 차이점

  • 객체포인터 변수에 부모클래스와 자식클래스를 담았을 때 오버라이딩된 함수를 실행하게 되면 무조건 부모함수를 실행하게 된다. 자식 클래스에서 재정의한 의미가 없어짐. 그렇기 때문에 virtual 이라는 키워드를 사용하여 가상함수로 만들게 된다면 객체포인터 변수에서 각각 해당하는 클래스의 함수를 호출하게됨.

  • 만약 부모클래스에서 재정의할 함수 앞에 virtual키워드를 사용하면 자식클래스는 키워드를 적지 않아도 컴파일러에서 자동으로 가상 함수로 정의가된다. 하지만 소스 코드의 이해를 돕기 위해 자식 클래스에서도 virtual 키워드를 적는 것이 관례.

  • 순수가상함수는 가상함수와 달리 함수의 선언만 있고 정의는 없는것으로, 자식 클래스에서 반드시 재정의하여야만 한다. 재정의 하지 않는다면 오류 발생

가상 테이블에 대해서 설명하시오

  • 클래스 안에 가상함수가 포함되어 있을시 객체를 생성할 때 가상함수를 가리키는 포인터가 생성된다.

  • 이 포인터는 가상테이블의 시작주소를 가리키는 포인터고, 각 클래스마다 하나의 고유 가상테이블이 생성되게 됩니다.

  • 고유의 가상테이블은 가상함수를 가리키는 함수포인터배열로 되어있다. 즉,가상 함수를 실행하려면 vptr->vtable->func()를 호출하게 되는 것

재귀함수

재귀함수란 함수 내에서 자기 자신을 다시 호추랗는 형태
장점 : 소스코드의 간결화가 가능하다.
단점 : 연산 시간이 오래 걸린다. 또한, 잘못 작성시 프로그램이 무한루프에 빠질 수 있다.

디자인패턴을 사용하는 이유에 대해서 설명하시오

디자인패턴이라 여러 프로그래머들의 경험과 지혜를 모아서 공통적인 소프트웨어 디자인 문제를 해결하는데 도움이 될 수 있게 만들어 놓은 것

가장 대표적인 디자인패턴으로는 싱글톤이 존재. 싱글톤이란 전체 프로그램에서 단 1개의 객체를 생성하고 공유하는데 사용하는 패턴이다.

프레임워크란?

  • 특정 형태의 소프트웨어 문제를 해결하기 위해 상호 협력하는 클래스 프레임과 인페이스 프레임의 집합

  • 특정 개념들의 추상화를 제공하는 여러 클래스나 컴포넌트로 구성되며, 컴포넌트들은 재사용이 가능하다.

스택이란

  • 스택은 LIFO의 원리로 동작하는 선형적인 자료구조이다. 데이터가 들어가고 나오는 입구가 하나뿐이므로 입구로 들어간 데이터가 스택에 차곡차곡 쌓여있다가 들어간 반대 순서로 나온다. 마지막에 들어간 원소가 처음에 나온다.

  • CPU도 여러가지 정보을 저장하기 위해 스택을 사용하는데 이를 시스템 스택이라 한다.

큐란?

큐는 FIFO의 원리대로 동작하는 자료구조이다. 동일한 자료의 집합을 다룬다는 면에 있어서는 스택과 비슷하지만, 가장 먼저 들어간 자료가 가장 늦게 나온다는 점이 다르다.

Vector와 List의 차이점

  • 반복자의 레벨
    벡터는 요소들이 인접해 있으므로 임의 접근이 가능하지만,List는 노드가 흩어져 있으므로 양방향으로만 이동이 가능하다. 이는 +n 연산을 반복자가 지원하지 않으므로 순서 값으로 요소를 엑세스 하는 [n]연산자를 지원하지 않으며 at 함수도 당연히 지원하지 않는다.

List는 임의 위치를 상수 시간내에 액세스 할 수 없으며 반드시 순회를 해야만 원하는 요소를 찾으 수 있다. 임의접근 반복자를 요구하는 sort나 binary_search알고리즘은 list에서 사용할 수 없다.

  • 삽입 삭제 속도
    리스트는 각 요소들이 노드로 할당되어 링크에 의해 연결이 되어 있으므로 삽입 삭제시 링크만 조작해주면 된다. 요소들이 흩어져있다 하더라도 삽입,삭제시에 메모리 이동을 할 필요가 없으므로 어느 위치에서든 상수 시간내에 삽입,삭제가 가능하다.

이에 비해 벡터는 중간에서 삽입,삭제할 때 데이터를 밀고 당겨야 하므로 속도가 다소 느리다.

결론은 구조와 링크방식의 차이점에 기인한다. 읽기 속도가 중요하다면 벡터를 선택하는 것이, 삽입 삭제가 아주 빈번하다면 리스트가 낫다.

BST에 대해 설명하시오

이진탐색트리는 데이터의 삽입,삭제,탐색등이 자주 발ㄹ생하는 경우에 효율적인 구조로, 이진 트리이면서 같은 값으 갖는 노드가 없어야 한다.

왼쪽 서브 트리에있는 모든 데이터는 현재 값보다 작고 오른쪽 서브 트리에 있는 모든 노드의 데이터는 현재 노드의 값보다 크다.

파라미터와 아규먼트

파라미터 : 함수를 선언할 때 사용된 변수
아규먼트 : 함수가 호출되었을 때 함수의 파라미터로 전달된 실제 값

프레임워크와 라이브러리 차이

라이브러리 : 사용자가 흐름에 대한 제어를 하며 필요한 상황에 가져다가 쓸 수있다.
프레임워크 : 전체적인 흐름을 자체적으로 제어한다.

post-custom-banner

0개의 댓글