[C++] virtual 함수

KWANHO PARK·2025년 4월 19일

CPP

목록 보기
20/24
/*
	virtual function : 파생클래스에서 재정의할 것을 약속받은 멤버 함수
	Base 클래스의 멤버 함수에 virtual 키워드를 사용하여 생성
	virtual table 만들어지고, dynamic binding으로 동작
*/
#include <iostream>

class Base {
public:
	virtual void func1() {							// 가상 함수
		std::cout << "Base::func1()" << std::endl;
	}
	virtual void func2() {							// 가상 함수
		std::cout << "Base::func2()" << std::endl;
	}
	void func3() {
		std::cout << "Base::func3()" << std::endl;
	}
};

class Derived : public Base {
	void func1() override {							// 가상함수를 재정의하는 멤버함수 나타냄
		std::cout << "Derived::func1()" << std::endl;	
	}
	void func3() {
		std::cout << "Derived::func2()" << std::endl;
	}
	void func4() {
		std::cout << "Derived::func4()" << std::endl;
	}
};

int main()
{
	Base b;
	Derived d;
	Base* bptr = new Derived();	// upcasting

	bptr->func1();				// base 클래스의 func1()은 가상함수로 선언되어 Derived 클래스의 func1()이 호출	
	bptr->func2();				// base 클래스의 func1()은 가상함수로 선언되었지만 오버라이딩(재정의) 되지 않았음. 부모클래스의 함수가 호출됨
	bptr->func3();				// 포인터 타입의 호출 함수가 결정됨
	//bptr->func4();

	delete bptr;
	bptr = &b;
	bptr->func1();
	bptr->func2();
	bptr->func3();

	return 0

}

/* ┚ 포인터의 다형성으로 기초 클래스 타입의 포인터로 파생 클래스 객체 가키리면 접근은 기초 클래스 멤버로 제한
   이 ‹š 오버라이딩 된 파생클래스의 멤버를 사용하기 위해서는 기초 클래스의 멤버 함수를 가상함수로 만들면 됨
   이것은 컴파일 시 포인터형으로 바인딩되지 못하고 런타임에서 포인터가 어떤 객체를 가리키고 있는지에 따라 바인딩 함수 결정*/


//	Virtual Class - 순수 지정자를 가지는 메서드를 순수 가상 함수라과 함
//  순수 가상 함수를 가지는 클래스 : 추상 클래스
//  추상 클래스는 객체 생성 불가

#include <iostream>

class Cinterface {
public:
	Cinterface() {
		std::cout << "CInterface Constructor call\n" << std::endl;
	}
	virtual void getData() const = 0;		// 순수 가상 함수
};

class CinSub : public Cinterface {
public:
	CinSub() {
		std::cout << "CinSub Constructor call\n" << std::endl;
	}
	void getData() const override {
		std::cout << "Pure Virtual function()" << std::endl;
	}
};

int main()
{
	// Cinterface obj;		// 추상클래스는 객체 생성 불가
	CinSub obj;
	std::cout << "+++++++++++++++++++++++++++++++" << std::endl;
	obj.getData();
	return 0;
}

/*
	추상 자료형 이용해서 동적 할당된 객체를 참조할 때는
	메모리 해제 시 참조 타입의 소멸자만 호출되어 메모리 누수 발생
	상위 클래스의 소멸자를 가상으로 만들어 실타입의 소멸자도 호출해야 함
*/
#include <iostream>

class CTest {
private:
	int num;
public:
	CTest(int anum) : num(anum) {
		std::cout << num << ", " << "CTest Constructor call" << std::endl;
	}
	virtual ~CTest() {		// 가상 소멸자.
		std::cout << num << ", " << "CTest Destructor call" << std::endl;
	}
	virtual void vfunc() {
		std::cout << "CTest virtual function()" << std::endl;
	}
	void func() {
		std::cout << "CTest function()" << std::endl;
	}
};

class CTestSub : public CTest {
private:
	int subN;
public:
	CTestSub(int n1, int n2) : CTest(n1), subN(n2) {
		std::cout << subN << ", " << "CTestSub Constructor call" << std::endl;
	}
	~CTestSub() {
		std::cout << "+++++++++++++++++++++++++++++++++++++++++" << std::endl;
		std::cout << subN << ", " << "CTestSub Destructor call" << std::endl;
	}
	void vfunc() override {
		std::cout << "CTestSub function() override" << std::endl;
	}
};

int main()
{
	CTest obj(1);
	std::cout << "+++++++++++++++++++++++++++++++++++++++++" << std::endl;
	
	CTestSub obj2(2, 22);
	std::cout << "+++++++++++++++++++++++++++++++++++++++++" << std::endl;
	
	obj.func();
	obj.vfunc();
	std::cout << "+++++++++++++++++++++++++++++++++++++++++" << std::endl;
	
	obj2.func();
	obj2.vfunc();
	std::cout << "+++++++++++++++++++++++++++++++++++++++++" << std::endl;
	
	CTest* ptr = new CTestSub(3, 33);
	delete ptr;		// 가상 소멸자 없으면 부모 객체 소멸자만 실행됨(3 CTest Destructor call). 자식 객체 소멸자는 실행 안 됨
	

	return 0;
}

0개의 댓글