[필기테스트 대비] 내가 보기 위한 C++ 정리 2 (Overloading, C++ Style cast)
2024. 12. 2. 19:23ㆍOther/C++
Overloading
Overview
- class Derived : public Base
- public이 아닌 그 이상의 접근 제어자로 상속할 경우 해당 접근 제어자 이상의 제어자만 Derived에서 사용 가능
- Derived(): Base(),s(str)
생성자 호출 순서
- 기반 클래스의 생성자 호출
- 파생 클래스의 생성자 호출
함수 검색 순서
- 어떤 함수가 파생 클래스에 정의되어 있을 경우, 파생 클래스의 함수를 호출
- 없는 경우 기반 클래스에서 함수를 찾아 실행
is-a / has-a
- is-a 관계는 "사과는 과일이다" 식으로 일반화하는 관계
- 상속을 활용하여 정의하기에 적합
- has-a 관계는 "자동차는 엔진을 갖고 있다" 식으로 소유하는 관계
- Composition을 활용하여 정의하기에 적합
Cast
Explicit (Conventional) Cast
- T t = (T)someValue;
- 타입에 대한 체크가 없기 때문에 위험
C++ Style Cast
- static_cast
<T>(value) - dynamic_cast
<T>(value) - const_cast
<T>(value) - reinterpret_cast
<T>(value)
static_cast
- 컴파일 타임에 type-safe하게 형변환
- 타입이 명확하게 호환되어야 함
- 다형성이 지원되어야 할 경우 dynamic_cast를 사용해야 함 (static_cast는 unsafe할 수 있음)
dynamic_cast
- 런타임에 타입을 확인하고 변환
- 호환되지 않을 경우 예외가 발생하거나 nullptr을 반환
- DerivedClass * -> BaseClass * 또는 DerivedClass & -> BaseClass & 형식의 변환이 가능
- 가상 함수가 있는 클래스에서만 작동
const_cast
- 상수성을 임시로 제거하는 형변환
- 실제 객체가 const로 선언되어 있는 경우 UB 발생 가능
- 가능하면 사용하지 않는 것이 좋음
reinterpret_cast
- 비트 단위로 타입을 강제로 변환
- 기존 명시적 형변환과 같은 동작
Up-casting / Down-casting
- Base * basePtr = &derived;
- Derived * derivedPtr = static_cast
<Derived *>(basePtr);- 강제 다운캐스팅으로 인한 런타임 오류 발생 가능성
- Derived * derivedPtr = dynamic_cast
<Derived *>(basePtr);- type-safe하게 형변환 가능, 실패시 nullptr 반환
가상 함수
- virtual void f();
동적 바인딩
- 어떤 함수를 실행할지 런타임에 결정
- run을 virtual로 선언했을 경우, Base * basePtr = derivedPtr; basePtr->run()의 경우 Derived의 run 실행 (가상 함수를 이용하여 동적 바인딩이 이루어지므로)
- 그렇지 않을 경우 Base의 run 실행 (정적 바인딩이 이루어지므로)
Override 키워드
- (virtual) void f() override;
- 함수가 이미 기반 클래스에 정의되어 있고, 파생 클래스에서 오버라이드해야 하는 경우, override 키워드 사용하여 오버라이드 하지 않는 것을 방지 가능
virtual 소멸자
- 소멸자를 virtual로 선언하지 않는 경우 정적 바인딩으로 인해 Base 클래스의 소멸자가 호출되어 문제가 될 수 있음
vtable
- 가상 함수 테이블
- 가상함수가 하나라도 존재하는 클래스에 대해 vtable 생성
flowchart TD; subgraph Base bvtable[vptr] end subgraph v1[vtable] bf1[f1] bf2[f2] end subgraph Derived dvtable[vptr] f3 end subgraph v2[vtable] df1[f1] df2[f2] end v2 bvtable-->v1 dvtable-->v2 f3-->actualdf3["Derived::f3()"] bf1-->actualbf1["Base::f1()"] bf2-->actualbf2["Base::f2()"] df1-->actualdf1["Derived::f1()"] df2-->actualbf2 - 가상함수는 vptr을 거쳐 vtable을 통해 실행되므로 오버헤드가 발생
순수 가상함수
- virtual void f() = 0;
- 하나 이상의 순수 가상함수를 가진 클래스는 직접 생성이 불가 : 추상 클래스
- 추상 클래스에 대한 포인터 선언은 가능
다중 상속
- 상속하는 순서에 따라 생성자 호출
- 상속한 서로 다른 클래스에서 동일한 함수가 존재할 경우, ambiguos 에러 발생
- 다이아몬드 상속으로 인해 중복 문제 발생 가능
가상 상속
class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
- 다이아몬드 상속 문제 해결을 위해 가상 상속 후, 각각의 클래스 생성자 호출을 통해 해결 가능
- 기본 클래스의 인스턴스가 파생 클래스에 의해 한번만 생성
- B와 C가 A의 인스턴스를 직접 갖는 대신, vbptr(virtual base pointer)을 통해 간접적으로 참조
- vbptr은 vbtable(virtual base table)을 가리키고, a의 유일한 오프셋에 대한 정보가 저장 됨
- vbptr (virtual base class table pointer) 추가로 인한 오버헤드 발생
'Other > C++' 카테고리의 다른 글
| [필기테스트 대비] 내가 보기 위한 C++ 정리 1 (Const, Reference, Constructor, Overloading) (0) | 2024.12.02 |
|---|