개발개발/c++ 이론연습

c++ 이론테스트 2차

유잉유잉유잉 2024. 12. 27. 23:48
728x90
void* 타입에 대한 특징을 고르시오.
 
void 타입 변수의 주소만 저장이 가능하다.
 
역참조가 가능하다.
 
어떤 타입의 메모리 주소라도 저장이 가능하다.
 
하나의 주소를 저장하고 있다면 다른 주소를 저장할 수 없다.

 



다음 중 지역변수의 특징을 고르시오.

변수가 선언되면 프로그램이 종료될때까지 메모리가 유지된다.
 
지역변수는 모든 곳에서 접근하여 사용이 가능하다.
 
지역변수가 더이상 필요 없을 경우 언제든지 메모리에서 제거할 수 있다.
 
지역변수는 특정 코드블록에 소속되어 해당 코드블록 내부에서만 사용이 가능하다.
 

 




다음 중 지역변수의 특징을 고르시오.

변수가 선언되면 프로그램이 종료될때까지 메모리가 유지된다.
 
지역변수는 모든 곳에서 접근하여 사용이 가능하다.
 
지역변수가 더이상 필요 없을 경우 언제든지 메모리에서 제거할 수 있다.
 
지역변수는 특정 코드블록에 소속되어 해당 코드블록 내부에서만 사용이 가능하다.
 

 

 

다음 중 동적 할당의 특징을 고르시오.
 
프로그램이 시작될 때 메모리에 공간이 할당된다.
 
프로그램이 종료될 때 메모리에서 제거된다.
 
원하는 시점에 메모리에 공간을 할당할 수 있다.
 
동적할당은 배열 생성이 불가능하다.




구조체의 특징이 아닌 것을 고르시오.
 
다른 타입의 변수들을 하나로 모아 사용할 수 있는 기능을 제공한다.
 
인덱스를 이용하여 구조체를 구성하는 각 요소에 접근할 수 있다.
 
구조체도 포인터 타입 변수를 선언할 수 있다.
 
구조체도 배열 변수를 선언할 수 있다.



 

 

다음 중 레퍼런스의 특징을 고르시오.
 
대상을 참조하여 값을 변경할 수 있다.
 
참조 대상을 다른 대상으로 변경할 수 있다.
 
함수의 인자로 사용할 수 없다.
 
모든 타입의 레퍼런스 타입 변수가 생성 가능하다.

 




다음 중 클래스 복사생성자에 대한 설명으로 잘못된 것을 고르시오.
 
얕은 복사는 단순 데이터만을 복사한다.
 
깊은 복사는 데이터 뿐만 아니라 동적할당된 객체의 메모리를 새로 생성하여 데이터를 복사할 수 있다.
 
복사생성자의 인자는 const 해당클래스& 타입을 사용한다.
 
복사생성자는 상속 관계에서 사용할 수 없다.

 



다음 중 가상함수에 대해 잘못 설명한 것을 고르시오.
 
가상함수는 가상함수테이블에 가상함수의 주소가 저장된다.
 
가상함수는 반드시 자식클래스에 재정의 해야 한다.
 
가상함수는 순수가상함수를 만들 수 있다.
 
자식클래스의 가상함수에서 부모클래스의 가상함수를 호출할 수 있다.

 



CChild 클래스를 sizeof 할 경우 결과로 몇바이트가 나오는지를 작성하고 그 이유를 작성하시오.

class CParent
{
public:
    int  mA;

public:
    virtual void Output()
    {
    }
};

class CChild : public CParent
{
};

x64인 컴퓨터에서 구조체 멤버맞춤이 기본값일 경우 16바이트

x86인 컴퓨터에서 구조체 멤버맞춤이 기본값일 경우 8바이트

가상함수를 가지고 있기 때문에 가상함수 테이블이 만들어지며 객체는 가상함수테이블의 메모리 주소를 저장하기 위한 vfptr 포인터 변수 하나가 무조건 잡히게 된다. 따라서 구조체 멤버맞춤에 따라 큰 사이즈인 16바이트, 8바이트로 잡히게 된다. ( vfptr 8byte + int mA 4byte)




가상함수에서 사용할 수 있는 abstract, override, final 키워드에 대해 설명하시오.

abstract

- 클래스에서 사용 : 추상 클래스로 만들어준다..

- 가상함수에서 사용 : 순수가상함수로 만들어준다.

- 어디에 붙더라도 무조건 클래스를 추상화한다.

 

override

가상함수를 재정의 할 때 사용한다. 재정의된 가상함수가 부모 클래스의 함수와 동일한 형태인지 체크하여 다른 형태일 경우 에러를 발생시켜주는 기능.

 

final

-클래스 : final 키워드가 붙은 클래스는 더이상 상속 불가.

-함수 : final 키워드가 붙은 가상함수는 더이상 재정의가 불가능하다.



 

 

dynamic_cast 에 대해 설명하시오.

상속관계에 있는 클래스를 이용하여 생성한 객체를 형변환할 때 사용한다.

실제 사용된 객체를 부모 타입으로 형변환 하거나 부모 포인터 타입에 저장된 메모리 주소를 생성될 때 사용한 타입으로 형변환 하는것은 문제가 없다.

단, 실제 생성된 객체의 자식 타입 혹은 형제 타입으로의 형변환시 nullptr을 반환한다.




C++에서 사용하는 4가지 메모리 영역을 작성하고 각각의 메모리 영역에 대해 설명하시오.

스택 : 지역변수, 매개변수의 공간이 할당된다.

코드블록이 종료될 경우 메모리에서 제거된다.

 

데이터 : 정적변수, 전역변수 공간이 할당된다. 프로그램 종료시에 제거된다.

 

코드 : 바이너리 코드의 공간이 할당된다.

 

힙 :  동적할당된 공간이 할당된다. 제거 안할 경우 메모리 릭이 발생.




 

클래스 static 멤버변수와 static 멤버함수에 대해 설명하시오.

static 멤버변수 : 이 클래스를 이용하여 생성한 모든 객체가 공유하는 메모리 1개가 만들어진다.

일반 멤버함수 : this가 필요하다. 그렇기 때문에 this에 들어갈 호출 객체를 반드시 지정해야 한다.  객체.함수()  를 할 경우 객체의 메모리 주소가 this에 들어간다.

static 멤버함수 : this가 없다. 그렇기 때문에 객체 차원에서 접근할 필요가 없다.

this가 없기 때문에 일반 멤버변수는 사용이 불가능하다.

단, static 멤버변수는 사용이 가능하다.

 





다음 중 템플릿에 대한 설명으로 맞는 것을 고르시오
 
다양한 타입을 모아 한번에 사용할 수 있다
 
열거형과 함께 사용한다
 
클래스, 함수, 구조체에 지정하여 원하는 타입으로 지정할 수 있다
 
어떤 타입의 메모리 주소라도 저장이 가능한 타입을 만든다

 

 

템플릿 :

컴파일 타임에 결정이 남.

타입을 가변적으로 지정하여 사용하는것이 템플릿

컴파일타임에 어떤 타입인지 결정이 남.

런타임에 타입을 바꿀 순 없음.





다음 중 템플릿 특수화에 대해 맞는 것을 고르시오
 
템플릿 함수를 사용 할 때 특수 키워드를 활용하여 타입을 정할 수 있다
 
템플릿 함수를 원하는 타입마다 원하는 함수가 호출 될 수 있게 해주는 기능이다
 
가변 템플릿 인자를 활용하는 기능이다
 
클래스 멤버함수에는 사용할 수 없다




다음 중 extern 키워드에 대해 맞는 것을 고르시오
 
지역변수를 전역변수로 선언해주는 기능이다
 
변수를 정적변수로 만들어주는 기능이다
 
동적할당된 변수를 공유할 때 사용한다
 
전역변수를 외부변수로 만들어 다른 곳에서 사용할 수 있게 해주는 기능이다

 




함수 오버라이딩과 오버로딩에 대해 설명하시오.

오버로딩 : 같은 이름의 함수를 인자의 개수 혹은 타입을 다르게 하여 정의하는 것을 말한다.

오버라이딩 : 부모 클래스에 있는 함수를 자식 클래스에 동일한 형태로 재정의하는 것을 말한다.



 

깊은복사와 얕은복사의 차이점을 작성하시오

얕은 복사 : 멤버변수들의 값을 그대로 복사하는 방식

깊은 복사 : 동적할당된 메모리가 있을 경우 해당 메모리 크기만큼 공간을 할당하여 값을 복사하는 방식. 





 

이동생성자에 대해 설명하시오

rvalue 타입을 인자로 받는 생성자이다.

임시 변수에 할당된 메모리를 그대로 사용하게 하는 기능.









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

가상함수의 주소를 저장하는 배열.

가상함수를 가지고 있는 모든 클래스는 가상함수 테이블을 가지게 된다.

가상함수를 호출할 때 가상함수 테이블에 저장된 주소를 이용하여 호출한다.






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

클래스를 abstract 키워드를 이용하여 제작하거나 순수가상함수를 가지고 있는 클래스를 추상클래스라고 한다. 

추상클래스는 객체 생성이 불가능하다.자식클래스에 상속을 내려줄 목적으로 제작하는 클래스이다.





클래스의 this에 대해 설명하시오

자기 자신의 메모리 주소를 의미한다.

클래스의 일반 멤버 함수에서 사용이 가능하다.클래스의 static 멤버함수에서는 사용이 불가능하다.



함수포인터에 대해 설명하시오

함수의 주소를 저장하는 타입.

함수는 주소가 존재한다.

함수를 호출할 때 함수주소()의 형태로 호출이 된다.

함수포인터는 이러한 함수 구조를 저장하여 저장된 메모리의 함수를 호출해주는 기능이다.

 

 

 

new, malloc, free/delete 의 차이에 대해 설명하시오

new : 연산자. 지정된 타입의 크기만큼 공간을 할당하여 해당 타입의 포인터 타입으로 리턴한다. 생성자 호출 가능.

malloc : 함수. 사이즈를 인자로 넘겨주고 그 크기만큼 공간을 할당하여 void*로 리턴한다. 생성자 호출 불가능.

delete : 연산자. 소멸자 호출 가능. 배열 제거시 delete[] 사용.

free : 함수. 소멸자 호출 불가능. 배열 제거시에도 동일하게 사용 가능.

 



std::shared_ptr의 문제점과 해결방안에 대해 설명하시오

스마트 포인터 사용. 참조하는 대상이 없을 경우 메모리 제거.

문제점 : A와 B객체가 있고, A는 B의 sharedptr, B는  A의 sharedptr을 가지고 있을 경우 순호나 참조가 되어 객체가 해제되지 않아서 메모리 릭이 발생한다.

멀티쓰레드 환경에서도 문제가 생길 수 있다.

해결방안 : std::week_ptr을 이용하여 순환참조를 끊어준다.



 

메모리 단편화 원인에 대해 설명하고 해결책을 작성하시오

메모리 단편화 : 동적할당을 이용하여 빈번하게 생성, 해제가 일어나게 될 경우 메모리가 여러 조각으로 나뉘어서 중간중간 작은 메모리들이 남아있는 문제를 말한다. 이 경우 작은 메모리는 사용할 수 없는 경우가 생기게 되기 때문에 메모리 효율성 문제가 발생한다. (외부단편화)

해결책 : 메모리풀 (미리 공간을 많이 할당하고 그 메모리를 사용하는 방법) 사용.

 

 

 

메모리 풀에 대해 설명하시오:

미리 공간을 많이 할당하고 그 메모리를 사용하는 방법 사용.

미리 만들어두기 때문에 너무 큰 공간을 만들고 다 사용을 안할 경우 공간 낭비가 될 수 있다.



 

const 위치에 따른 의미를 설명하시오
const int* a;
int* const a;
const int* const a;
void func(int _iValue) const
 
const int* a; : 참조하는 대상의 값을 변경할 수 없다.
int* const a; : 참조하는 대상을 변경할 수 없다. 
const int* const a; : 참조하는 대상의 값을 변경할 수 없고 참조하는 대상도 변경할 수 없다.
void func(int _iValue) const : 이 함수에서 멤버변수의 값을 변경할 수 없고, const 객체도 호출 가능한 함수가 된다.



 

RTTI에 대해 설명하시오

Real Time Type Infomation 의 약자이다.

실행 시간에 객체의 타입 정보를 확인할 수 있는 기능을 제공한다.

dynamic_cast, typeid가 RTTI를 활용한 기능들이다.



 

C++의 4가지 형변환에 대해 설명하시오

static_cast : 컴파일 타임에 처리되는 변환. 가장 기본이 되는 타입변환

dynamic_cast : 런타임에 처리되는 변환. 다형성을 가진 객체만 사용 가능.

const_cast : const 속성 해제.

reinterpret_cast : 컴파일러가 타입 변환에 대한 검사 없음. 그렇기 때문에 형변환이 다 가능하지만 안정성에 대한 책임은 없다. 강제로 형변환을 시켜버린다.



 

 

다음 코드의 출력값을 작성하고 그렇게 나오는 이유를 작성하시오.

struct Test
{
  int a = 0;
  float c = 0.f;
  char b = 0;
  short d = 0;
  char* e;
}

void main()
{
  std::cout << sizeof(Test) << std::endl;
}

 

24바이트. 

가장 큰 크기가 8바이트이므로 

int, float 8바이트

char, short, 패딩 8바이트

char * 8바이트

가 된다.

단 구조체 멤버맞춤에 따라 크기가 다르게 잡힐 수 있다.

x86일 경우에도 다르게 잡힌다(16바이트)

 


재귀함수와 꼬리재귀함수에 대해 설명하시오

재귀함수 : 자기자신을 호출하는 함수. 

각 호출마다 스택이 쌓이게 된다. 

 

꼬리재귀함수 : 

자기자신을 호출하는 부분이 함수의 마지막에 호출되는 형태.

재귀 호출이 끝나면 아무 일도 하지 않고 결과만 바로 반환되도록 하는 방법.

컴파일러가 재귀함수를 최적화하여 반복문으로 동작되게 만들어주는 방식. 

반복문으로 취급되면 스택 오버플로우 방지가 가능하다.



 

다음 코드의 반복 횟수를 작성하고 그 이유를 작성하시오

unsigned int a = 150;

for(unsigned char i = 0; i < a*2; ++i)

{

}

무한반복.

unsigned char 는 0 ~ 255까지 표현이 가능하다. 그런데 150 * 2이므로 300보다 작을 때 동작하게 되는데 ++를 반복하면 i는 255에서 256이 되는 순간 0이 된다. 그러므로 무한 반복하게 되는 것이다.

 



다음 코드의 문제점과 해결 방안을 작성하시오

int Division(int a, int b)
{
        return a / b;
}

b가 0일때 0으로 나누게 되기 때문에 문제가 발생한다.

예외처리를 통해 b가 0일 경우에 대한 예외처리를 해주어야 한다.

 



 

 

다음 코드의 출력값을 작성하고 그 이유에 대해 작성하시오

void foo(int* p, int* q)
{
    p = q;
    *p = 3;
}

 

int main(void)
{
    int i = 1, j = -1;

    foo(&i, &j);

    printf("%d, %d", i, j);
}

1,3

foo 에서

p = q ; // p(i)가 q(j)의 주소를 가지게됨 

*p = 3 ; // p(j)의 주소의 값에 (역참조) 3 대입  

 

 

다음 코드의 출력 결과를 작성하고 그 이유에 대해 작성하시오

class CParent
{
public:
    CParent()
    {
    }
    virtual ~CParent()
    {
    }
}

class CChild : public CParent
{
    CChild()
    {
    {
    ~CChild()
    {
    }
}

void main()
{
    std::cout << sizeof(CChild) << std::endl;
}

가상함수가 있기 때문에 x64 : 8바이트

x86 : 4바이트가 나온다. 

 

 

 

다음 함수에서 Target 변수의 n번째 비트를 Flag에 따라 온/오프 시킬 수 있도록 함수를 완성하시오.

void Func(int& Target , int n, bool Flag)

 

if (Flag)
Target |= ( 1 << n ) ;

else
Target &= ~( 1 << n );

 



 

싱글톤 패턴의 장점과 단점에 대해 작성하고 예제코드를 작성하시오

장점 : 어디서든 접근이 가능하다. 원하는 타이밍에 객체를 생성할 수 있다.

단점 : 어디서든 접근이 가능하다. 너무 많은 곳에서 접근하게 되면 클래스 구조 설계가 엉망이 될 수 있다.

 

 


아래 코드에서 문제가 발생할 수 있는 부분을 작성하기

#include <iostream>

class CParent
{
public:
    CParent()
    {
        std::cout << "CParent 생성자" << std::endl;
    }

    ~CParent()
    {
        std::cout << "CParent 소멸자" << std::endl;
    }
};

class CChild : public CParent
{
public:
    CChild()
    {
        std::cout << "Child 생성자" << std::endl;
    }

    virtual ~CChild()
    {
        std::cout << "Child 소멸자" << std::endl;
    }
};

int main()
{
    CParent* p = new CChild;

    delete p;

    return 0;
}

CParent 소멸자 호출시 crash 발생.

자식 클래스는 소멸자가 virtual 함수이기 때문에 가상함수테이블을 가지고 있지만 

객체 p는 CParent 타입으로 변수를 선언했기 때문에 부모타입은 가상함수 테이블을 가지고 있지 않음.

728x90