개발개발/c++

c++의 순수가상함수, 오버라이드, 다중상속, final, 생성자에서 initialize

유잉유잉유잉 2024. 12. 16. 10:16
728x90

▶️ 순수가상함수 

  • 부모클래스의 함수를 자식 클래스에서 반드시 재정의하도록 명시하는 함수입니다.
  • 자식 클래스에서 순수가상함수가 선언되지 않으면 에러가 납니다.
  • 부모클래스에서 순수 가상함수에 구현부를 만들 수 있습니다 (안만들어도 됩니다)
// A.h
class A
{
// 일반 가상함수 선언
// 자식함수에서 재정의 하지 않아도 사용가능
virtual void Pure();
// 순수가상함수 선언
virtual void Test() = 0; 
virtual void Test2() abstract ;
}

class B : public A
{
virtaul void Test();
virtual void Test2();
}

class C : public A
{
virtual void Pure();
virtual void Test();
}

class main()
{	
	// 가능
	B * b = new B ;
    
    // 에러 : Test2()를 재정의하지 않아서 사용할 수가 없음
    C * c = new C; //[에러] 추상 클래스 형식 "C"의 개체를 사용할 수 없습니다.
    
	return 0;
}

 

 

▶️ 순수가상함수 선언방법 두가지

  1. 함수명 뒤에 0을 넣기
  2. 함수명 뒤에 abstract 키워드 붙이기

 

 

 

▶️추상클래스 

  • 객체 생성할 필요 없을 경우 선언하여 사용합니다
  • 순수가상함수를 하나라도 가지고 있는 클래스를 추상클래스라고 합니다. 
  • 순수가상함수는 자식 클래스에서 반드시 재정의 해야합니다.
  • 자식클래스에서 순수가상함수가 재정의가 안될 경우, 자식 클래스 또한 추상클래스로 취급됩니다.
  • 추상 클래스 선언방법 : 클래스명 뒤에 abstract 키워드 추가
class A abstract 
{
}

void main()
{
	// 추상 클래스라서 객체 생성 불가 
	A * a = new A;
}

 

 

▶️ override

  • override 키워드는 이 함수가 부모의 함수를 재정의한 함수임을 명시합니다.
  • 만약 부모 클래스의 함수들 중 같은 형태의 함수가 없다면 이 함수는 에러를 발생시킵니다
  • 함수를 재정의하며 생기는 에러를 줄여줍니다.
// A.h
class A abstract
{
public :
	virtual void Test();
    virtual void Test2(int num);
}


// B.h
#include "A.h"
class B : public A
{
public :
	virtual void Test() override ;
    virtual void Test2(int num, int num) override ; // 에러. 부모의 함수 형태와 다름
}

 

▶️ 다중상속

여러 부모를 상속받는 기능입니다.

class A
{
}

class B
{
}

// class C는 A와 B를 둘 다 상속받습니다.
class C :
	public A, public B
{
}

 

▶️ 다중상속 주의점

변수명이나 함수명이 겹치면 문제가 생길 수 있으니 주의해서 사용하세요

class A
{
public : 
	int num;
    int num2;
	float num3;
}

class B
{
public :
	int num;
    char ch;
;

class C 
	: public A, public B
{
}

void main()
{
	C * c = new C;
    c->num ;// A의 num인지 B의 num인지 확인이 어려움  
}

 

 

▶️ Final

- 함수에서 사용

  • 해당 클래스를 상속받은 자식 클래스에서 더이상 재정의 할 수 없게 명시적으로 표현합니다.
  • 함수명 뒤에 final을  붙여서 선언합니다
class A
{
public :
	void Output() final ;
}

class B : public A
{
public :
	void Output() ; // [에러] final 함수 재정의 불가
}

 

- 클래스에서 사용 : 

  • 상속을 받을 수 없는 클래스로 만들어줍니다. ( 부모클래스로 사용할 수 없습니다 )
  • 클래스 명 뒤에 final 키워드를 붙여서 선언해줍니다.
class A final
{
}

class B
: public A // 상속불가 
{
}

 

 

▶️ 자식 생성자에서 부모 생성자함수 먼저 호출하기 

// A.h
class A
{
public :
	A();
    A( const A& obj );
    ~A();
    
public : 
	virtual A* Clone();
}

// A.cpp
A::A(){}
// 인자로 들어오는 오브젝트를 대입하여 모든 멤버변수를 얕은복사로 복사하기 
A::A( const A& obj )
{
	*this = obj;
}


// B.h
class B 
	: public A
{
public :
	B();
    B( const B& obj);
    ~B();
    
public :
	virtual B* Clone();
}

// B.cpp
B::B(){}
B::B(const B& obj ) : A(obj) // <--------------
{
}
B* B::Clone()
{
	new B(*this);
}

 

 

▶️ 매크로

  • 매크로는 디버깅이 되지 않기 때문에 디버깅이 필요없는곳에서만 사용하길 권장합니다.
  • 한줄로 써야하지만 한 줄이 넘어갈 경우 문장 맨 끝 마지막마다 (\)를 붙여줍니다
    • \뒤에 공백등 문자가 들어갈 경우 에러가 발생합니다.. (^^...)
    • 장문의 맨 마지막 문장엔 \를 안붙여야 합니다
  • ex: 싱글턴패턴, 메모리 제거 매크로 등
// GameInfo.h

#include <iostream>

#define SAFE_DELETE(p)	{ delete p; p = nullptr; }

#define DECLARE_SINGLE(type) \
private : \
	type(); \
    ~type(); \
private : \
	static type * mInst; \
public : \ 
	static type * GetInst() \
    { \
    	if( nullptr == mInst ) \
        	mInst = new type ; \
        return mInst; \
    } \
    static void DestroyInst() \
    { SAFE_DELETE( mInst ); }
    
#define DEFINITION_SINGLE(Type) type* type::mInst = nullptr;

 

 

▶️ 생성자에서 변수 초기화하기 

class A 
{
public :
	A() : num(0), option(0)
    
public :
	int num = 0;
    int option = 0;
}

class B : public A
{
public : 
	B() : num(0) // ----> 에러 부모 클래스의 변수는 생성자에서 이니셜라이징 불가능하다 
    {
    	num = 0; // 이런식으로 해야함 
    }
    
public :
	int buy = 0;
}

 

728x90