명시적으로 정의되어 있지 않을 경우,,,,컴파일러가 제공하는 디폴트
할당 연산자 함수가 호출되어...Shallow Copy(얕은 복사) 라고 하는
객체의 멤버변수별 일대일 복사가 이루어 집니다...
함수가 복사가 되는 것이 아닙니다...
i = b.fs(); // 이러면 2를 반환
a = b;
i = a.fs(); // 이러면 1을 반환
==> 당연히,,,fs( ) 함수는 무조건....1 혹은 2를 리턴하게 되어 있으니
복사하고는 관련이 없죠...
B 클래스 객체를 A 클래스 객체에 할당하여...A 클래스 객체가 B 클래스
객체의 속성(멤버변수) 값을 가지려면...아래와 같이 해보시길...
단순히,,,객체의 멤버변수가 대입되는 것이죠...
class A{
int a;
public :
A( ) : a(10) { }
A(int _a) : a(_a) { }
int fs( ) { return a; }
};
class B : public A{
int b;
public :
B( ) : A(30), b(20) { }
int fs( ) { return b; }
};
void main()
{
A obA;
B obB;
// obB 객체의 B에 대한 부분은 잘려나가고...
// obA 객체는 여전히,,,자신의 속성(a) 만을 취합니다...
// 즉,,,slicing problem 이 발생하는 거죠....
// 다만,,, obB가 가지고 있었던 A 클래스 타입의 속성(a) 값 30이
// obA 객체의 a 값으로 복사되어 들어갑니다...
obA = obB;
cout<< obA.fs() <
그러므로,,, a = b 라는 연산이 쓸모없는 것이 아니라,,,
질문자가 물어본 방법에서는 fs( ) 함수가 무조건 1 혹은 2를 리턴하도록
되었기 때문에 객체의 속성값(멤버변수) 과는 관련이 없습니다...
함수는 복사되는게 아닙니다...
그리고,,,포인터 자신은 무조건 4바이트(32비트 환경) 이지만...
포인터 자신이 가리키는 곳이 얼만큼의 크기를 가졌는지 고려해야죠...
즉,,,포인터의 타입이 각기 다른 이유는 어느 정도의 크기를 읽어 들여야 할지
알아야 하기 때문입니다...
포인터 간의 대입도...업 / 다운 형변환을 고려해야 합니다...
상속관계에서는 기본적으로 업 캐스팅은 지원되고,,,다운 캐스팅은 오류로
처리할 겁니다...
대충...이 정도면 3번까지의 대답은 어느정도 되었을 것 같구요...
마지막으로...
virtual을 사용 안 했다고 해도 컴파일할 때 상위클래스의 포인터객체가
하위클래스 객체의 주소를 받았다면 하위클래스멤버함수로 바인딩시킬 수
있지 않겠습니까? (질문한 내용...)
==>> virtual 이 붙은 함수들은 컴파일러가 따로...가상함수 테이블을 생성하여
관리합니다...
일반 멤버함수와 같은 것이 아니죠...
가상함수 테이블은 보통,,,함수 포인터 배열로 이루어져 있다고 하네요...
예를 든다면...
A *pA;
B obB;
pA = &obB;
이런 것을 마지막에 물어 보신것 같은데...
만약,,,,A 클래스의 어떤 멤버함수가 virtual 이 아니고,,,이 함수를 그대로
B 클래스에서 오버라이딩 하였다면...비록,,,포인터 pA가 B 클래스 타입의
객체를 생성하였다고 해도...포인터 자신의 선언 타입이 A 클래스 타입이기
때문에...B 클래스에 있는 오버라이딩 된 함수를 알지 못합니다...
이미,,,정적 바인딩에 의해...호출될 함수가 사전에 결정되었기 때문이죠...
그러나,,,,virtual 이 붙은 가상함수는 가상함수 테이블에 각각의 함수에 대한 주소를
갖도록 하여...나중에...컴파일러가 동적 바인딩을 하여...포인터가 가리키는 클래스
타입에 따라...원하는 함수를 호출할 수 있도록 하는 것이죠...
더욱 자세한 사항은 다형성, 가상함수 부분을 집중적으로 보세요...
댓글 없음:
댓글 쓰기