사용방법
class First { public: virtual void MyFunc() { ... } };
자식 클래스의
void MyFunc()
즉 오버라이딩 된 함수는 모두 가상함수가 된다
규칙
1. 클래스의public
영역에 선언
2. 가상함수는 static일 수 없으며 다른 클래스의 friend가 될 수 없다
3. 가상함수는 기본 클래스의 포인터 또는 참조를 통해서 접근해야함(실행시간의 다형성 얻기 위함)
4. 가상함수의 프로토타입(반환형과 매개변수)은 기본클래스와 파생클래스에서 동일
5. 클래스는 가상 소멸자를 가질 수 있지만 가상 생성자를 가질 수 없다
다형성이란 '동질이상'을 의미한다.
"모습은 같은데 형태는 다르다" => "문장은 같은데 결과는 다르다
#include <iostream> using namespace std; class First { public: virtual void SimpleFunc() { cout << "First" << endl; } }; class Second :public First { public: virtual void SimpleFunc() { cout << "Second" << endl; } }; int main() { First* ptr = new First(); ptr->SimpleFunc(); delete ptr; ptr = new Second(); ptr->SimpleFunc(); delete ptr; return 0; }
위 main함수에는ptr->SimpleFunc();
라는 문장이 두 번 등장한다
- ptr은 동일한 포인터 변수인데 실행결과가 다른 이유
- 포인터 변수 ptr이 참조하는 객체의 자료형이 다르기 때문
#include <iostream>
using namespace std;
class First
{
public:
void MyFunc() { cout << "FirstFunc" << endl; }
};
class Second :public First
{
public:
void MyFunc() { cout << "SecondFunc" << endl; }
};
class Third :public Second
{
public:
void MyFunc() { cout << "ThirdFunc" << endl; }
};
int main()
{
Third* tptr = new Third();
Second* sptr = tptr;
First* fptr = sptr;
fptr->MyFunc();
sptr->MyFunc();
tptr->MyFunc();
delete tptr;
return 0;
}
#include <iostream>
using namespace std;
class First
{
public:
virtual void MyFunc() { cout << "FirstFunc" << endl; }
};
class Second :public First
{
public:
virtual void MyFunc() { cout << "SecondFunc" << endl; }
};
class Third :public Second
{
public:
virtual void MyFunc() { cout << "ThirdFunc" << endl; }
};
int main()
{
Third* tptr = new Third();
Second* sptr = tptr;
First* fptr = sptr;
fptr->MyFunc();
sptr->MyFunc();
tptr->MyFunc();
delete tptr;
return 0;
}
#include <iostream>
using namespace std;
class Super {
public:
virtual void func1() { cout << "Super::func1()" << endl; }
virtual void func2() { cout << "Super::func2()" << endl; }
void func3() { cout << "Super::func3()" << endl; }
};
class Sub : public Super
{
public:
void func1() { cout << "Sub::func1()" << endl; } // virtual 함수를 상속받았기 때문에 자동으로 virtual이 생성됨(선언안해도 생성된다)
void func2() { cout << "Sub::func2()" << endl; }
void func3() { cout << "Sub::func3()" << endl; }
void func4() { cout << "Sub::func4()" << endl; }
};
int main()
{
Super super;
Sub sub;
super.func3();
super.func2();
super.func1();
sub.func4();
sub.func3(); // Super 클래스의(부모클래스) 메소드 상속
sub.func2(); // Sub 클래스의 메소드에 가려져서 부모클래스의 메소드는 가려짐
sub.func1();
cout << endl;
Super* ps = new Sub; // 자식객체를 부모포인터로 연결한다.
ps->func3(); // 포인터로 부모클래스에 접근한다
ps->func2(); // 포인터 타입(Super)기준으로 접근
ps->func1();
// virtual 사용하면 자식클래스 접근 가능 ...
delete ps;
return 0;
}
부모클래스인
class Super
에서virtual void func1()
선언 ...class Sub : public Super
에서void func1()
이지만 부모클래스를 상속받았기 때문에 자동으로 가상함수가 된다
#include <iostream>
using namespace std;
class First {
private:
char* strOne;
public:
First(char* str) {
strOne = new char[strlen(str) + 1];
}
~First() {
cout << "~First()" << endl;
delete[]strOne;
}
};
class Second :public First
{
private:
char* strTwo;
public:
Second(char* str1, char* str2) :First(str1)
{
strTwo = new char[strlen(str2) + 1];
}
~Second()
{
cout << "~Second()" << endl;
delete[] strTwo;
}
};
int main()
{
First* ptr = new Second("simple", "complex");
delete ptr;
return 0;
}
-> 자식클래스의 소멸자 호출이 안되고있음
virtual키워드로 해결 가능
#include <iostream>
using namespace std;
class First {
private:
char* strOne;
public:
First(char* str) {
strOne = new char[strlen(str) + 1];
}
virtual ~First() {
cout << "~First()" << endl;
delete[]strOne;
}
};
class Second :public First
{
private:
char* strTwo;
public:
Second(char* str1, char* str2) :First(str1)
{
strTwo = new char[strlen(str2) + 1];
}
virtual ~Second()
{
cout << "~Second()" << endl;
delete[] strTwo;
}
};
int main()
{
First* ptr = new Second("simple", "complex");
delete ptr;
return 0;
}