07.22

신승빈·2022년 7월 22일
0

KGCA 수업

목록 보기
11/128

다형성(Polymorphism)

다형성 = 가상함수
가상함수가 구현된 class는 memcpy할 경우 vfptr도 함께 복사됨.
함수의 복사는 복사 생성자, 대입 연산자를 이용하는 것이 좋음.

소멸자와 virtual

class Parent
{
    int* pParent;
public:
    Parent()
    {
        pParent = new int;
    }
    ~Parent()
    {
        delete pParent;
    }
};

class Child : public Parent
{
    int* pChild;
public:
    Child()
    {
        pChild = new int;
    }
    ~Child()
    {
        delete pChild;
    }
};

int main()
{
    Parent* p = new Child;
    delete p;
    
    return 0;
}

소멸자를 virtual 선언하지 않을 경우, 위의 상황에서 pChild는 해제되지 않음.
메모리 누수 발생.

예외처리(throw-try-catch)

기존함수

bool div(int a, int b, int* result)
{
	if(b == 0)
    	return false;
    result = a / b;
    return true;
}

기존 함수에서의 예외처리는 return값을 통해 처리
전달할 수 있는 정보의 양이 한정적임.

예외처리

class Exception
{
...
};

void func()
{
    throw 1;
    throw 3.0f;
    Exception e;
    throw e;
}

int main()
{
    try
    {
        func();
    }
    catch(int i)
    {

    }
    catch(float f)
    {

    }
    catch(Exception e)
    {

    }
    catch(...)
    {

    }
    
    return 0;
}

다양한 정보 전달 가능.
값에 맞는 catch가 지정되어 있으면 문제 없음.
중첩된 catch의 경우 가장 가까운 catch로 이동.
catch 내부에서 throw도 가능(중계).

주의사항

class Parent { };
class Child : public Parent { };

void func()
{
    throw Child();
}

int main()
{
    try
    {
        func();
    }
    catch(Parent p)
    {
        cout << "Parent" << endl;	//Parent Catched
    }
    catch(Child c)
    {
        cout << "Child" << endl;
    }
    
    return 0;
}

catch 구문의 순서는 파생클래스부터 잡도록 해야함.

void func() throw(type1, type2);

함수의 정의부에 던질 예외를 미리 적어둘 수 있음.
구현과 달라도 상관은 없음.

표준 예외 클래스

cpp에서는 표준으로 정해둔 예외 클래스가 존재.
클래스에 필요 정보를 채워 클래스 단위로 예외를 보내는 것이 좋음.

참고 : https://ansohxxn.github.io/cpp/chapter14-4/

유용한 매크로

--FILE-- : 파일의 전체 경로
--LINE-- : 현재 라인
--FUNCTION-- : 현재 함수 명

참고 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=dnjsjd11&logNo=220835540920

noexception 키워드

함수가 예외를 발생시키지 않는다면 noexception을 통해 함수 정의부에 명시.
실제로 예외를 던져도 문제는 없지만 예외 처리가 불가능.
컴파일러의 추가 최적화 수행.
cpp11부터 소멸자는 기본적으로 noexception.

참고 : https://modoocode.com/230#page-heading-7

catch의 흐름

void func2()
{
    throw 'c';
    cout << "Func2" << endl;
}
void func1()
{
    func2();
    cout << "Func1" << endl;
}

int main()
{
    try
    {
        func1();
    }
    catch(char c)
    {
        cout << "Catch" << endl;
    }
    
    return 0;
}

throw된 exception은 가장 가까운 catch로 넘어가고 throw이후의 구문은 수행되지 않음.
위의 경우 Catch만 출력되고 Func1, Func2는 출력되지 않음.

Stack Unwinding

void func2()
{
	int* pInt = new int;
    throw 'c';
    cout << "Func2" << endl;
    delete pInt;
}
void func1()
{
    func2();
    cout << "Func1" << endl;
}

int main()
{
    try
    {
        func1();
    }
    catch(char c)
    {
        cout << "Catch" << endl;
    }
    
    return 0;
}

위의 상황에서 pInt는 해제되지 않음.

RAII(Resource Acquisition Is Initialization)

모든 리소스의 동적 할당은 생성자에서만 수행.
이를 통해 Stack Unwinding 과정에서 발생하는 Memory Leak 방지 가능.

Cast

클래스, 상속의 발생에 의해 추가됨.

const_cast

상수성(const), 휘발성(volatile) 제거.

reinterpret_cast

무조건 수행.
비트 재해석.
void*에서 쓸 수 있을 듯.
HashMap에서 사용?

static_cast

c의 casting.
상속 관계.
런타임 검사 없음.

class Parent
{
	void pFunc();
    ...
};
class Child : public Parent
{
	void cFunc();
    ...
};
int main()
{
	Parent* pParent = new Parent;
    Child* pChild = static_cast<Child*>(pParent);
    pChild->cFunc();	// 위험

다운캐스팅 가능 -> 위험

형변환 오버로딩
class AClass
{
public:
	int m_iValue;
	// BClass로 케스팅되는 방법을 알려준다.
	operator BClass();
};
AClass::operator BClass()
{
	// 멤버초기화
	BClass fRet = { static_cast<float>(m_iValue) };
	return fRet;
};

이 경우 static_cast가 가능.

dynamic_cast

상속 관계.
런타임 검사 수행. 실패시 NULL 반환.
부모에 virtual function 필수. type_id가 vfptr에 추가됨.

참고 : https://dataonair.or.kr/db-tech-reference/d-lounge/technical-data/?mod=document&uid=235810

RTTI와 Reflection

객체의 메모리를 참조하여 객체에 대한 정보를 얻는 것.
둘 다 큰 차이는 없는 듯.

profile
이상을 길잡이 삼아 로망을 추구합니다.

0개의 댓글