1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#include <iostream>
class A
{
public:
A() {};
int b = 10;
void print()
{
std::cout << b << std::endl;
}
};
class B : public A
{
public:
B() {};
int a = 20;
void print()
{
std::cout << a << std::endl;
}
};
class C : public A
{
public:
C() {};
int c = 30;
void print()
{
std::cout << c << std::endl;
}
};
int main()
{
A* a = new B();
a->print();
a = new C();
a->print();
}
|
cs |
출력값 : 10, 10
virtual 키워드의 경우는 '최적화' 를 무시하고 컴파일러가 실제 메모리 주소를 확인하게 하기 위해서 존재한다.
만약 virtual 을 자식객체에 붙인 뒤, 다운캐스팅 하여 자식 객체를 사용하려는 목적으로 사용한다면
출력값은 올바르지 않을것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#include <iostream>
class A
{
public:
A() {};
int b = 10;
void print()
{
std::cout << b << std::endl;
}
};
class B : public A
{
public:
B() {};
int a = 20;
virtual void print()
{
std::cout << a << std::endl;
}
};
class C : public A
{
public:
C() {};
int c = 30;
virtual void print()
{
std::cout << c << std::endl;
}
};
int main()
{
A* a = new B();
a->print();
a = new C();
a->print();
}
|
cs |
출력값 : 10, 10
자식객체에 virtual 을 암만 입력 해 봤자 C++ 에서는 프로그래머가 의도한 동작이 발생하지 않는다.
C++ 에서는 최적화를 위해 컴파일러가 할당받은 실제 메모리 주소가 아닌,
메모리의 형 (shape) 만 보고 어림짐작으로 해당 객체내의 method 를 참조하기 때문이다.
실제 메모리에 뭐가 들었는지 확인은 안하고 껍떼기만 보고 '이거겟거니~' 하고 실행시키는 거다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
#include <iostream>
#include <math.h>
class A
{
public:
A() {};
int b = 10;
virtual void print()
{
std::cout << b << std::endl;
}
};
class B : public A
{
public:
B() {};
int a = 20;
void print()
{
std::cout << a << std::endl;
}
};
class C : public A
{
public:
C() {};
int c = 30;
void print()
{
std::cout << c << std::endl;
}
};
int main()
{
A* a = new B();
a->print();
a = new C();
a->print();
}
|
cs |
출력값 : 20, 30
자식객체에 virtual 이 붙어있건 아니던 전혀 상관이 없다.
부모객체에만 virtual 이 붙어있다면.
다운캐스팅 시에 '형' 만 보고 어림짐작으로 해당 형의 선언부 method 를 실행시키지 않고,
해당 형이 담긴 '메모리' 를 직접 파고들어, 해당 메모리 내에 존재하는 실제 method 를 실행시킨다.
즉 '자식' 클래스에 붙는 virtual 의 경우는 그냥 '안붙여도 된다'
하지만, 해당 함수가 '재 정의' 되었음을 알려주기 위해 override 예약어를 붙이는걸 추천한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include <iostream>
class A
{
public:
A() {};
int b = 10;
virtual void print()
{
std::cout << b << std::endl;
}
};
class B : public A
{
public:
B() {};
int a = 20;
void print() override
{
std::cout << a << std::endl;
}
};
class C : public A
{
public:
C() {};
int c = 30;
void print() override
{
std::cout << c << std::endl;
}
};
int main()
{
A* a = new B();
a->print();
a = new C();
a->print();
}
|
cs |
출력값 : 20, 30
위와 같이 override 예약어를 붙일 경우, 명시적으로 해당 method 가 부모 class 를 재정의 함을
'프로그래머' 에게 알리고, 나아가 컴파일러에게도 알릴 수 있다.
override 를 붙었는데, '이름만 같고, 형식은 다른' method 를 정의한다면 에러가 발생하여
보다 생산성을 높일 수 있다.
'Programming > C++' 카테고리의 다른 글
[C++] 동적 라이브러리 vs 정적 라이브러리 개인 의견 (0) | 2021.08.22 |
---|---|
[C++] 인터페이스에 관한 팁 (순수가상함수) (0) | 2021.06.09 |
[C++] openSSL Hash 사용법 (0) | 2021.05.12 |
[C++] C# 측으로 Struct 를 UDP 로 전송 (0) | 2021.04.15 |
[C++] OpenCV digit_svm 예제 간단 분석 (0) | 2021.03.31 |