18.9 Object slicing

7495 단어 c++_studyc++_study

https://www.learncpp.com/cpp-tutorial/object-slicing/

우리는 이제까지 Base ptr 혹은 ref로 derived class object를 받아와서 사용하곤 했다
이러한 경우에 object는 비록 Base prt, ref 타입이지만 원본은 Derived portion이 존재한다
그리고 virtual을 통해 이러한 부분에 접근할 수 있었다

하지만 단순히 Base object에 Derived object를 assign하면 어떻게 될까?

int main()
{
    Derived derived{ 5 };
    Base base{ derived }; // what happens here?
    std::cout << "base is a " << base.getName() << " and has value " << base.getValue() << '\n';

    return 0;
}

Derived class object는 base 파트를 지니고 있다. 위와 같은 경우 base object는 derived object에서 오직 Base portion만 복사해온다. 이러한 현상이 Derived portion이 잘려나간 것처럼 보이기에 object slicing이라고 부른다

Slicing and functions

이러한 slicing에 대해서 자세히 살펴보자

void printName(const Base base) // note: base passed by value, not reference
{
    std::cout << "I am a " << base.getName() << '\n';
}

위와 같은 함수를 정의하자 여기서 눈여겨볼 점은 parameter가 ref Base도 pointer도 아닌 일반적인 Base 타입이다.

int main()
{
    Derived d{ 5 };
    printName(d); // oops, didn't realize this was pass by value on the calling end

    return 0;
}

따라서 위처럼 Derived 타입을 argument로 넘겨주면 copy를 해가기에 object slicing이 일어난다 따라서 base.getName()은 Base::getName()을 호출한다

만약 함수가 다음과 같다면

void printName(const Base& base) // note: base now passed by reference
{
    std::cout << "I am a " << base.getName() << '\n';
}

int main()
{
    Derived d{ 5 };
    printName(d);

    return 0;
}

parameter가 Base ref인 경우이다
이런때에는 pass by ref이므로 Derived의 portion은 남아있다
따라서 getName()이 virtual 함수 이므로 Derived::getName()을 호출한다

The Frankenobject

우리는 이러한 slicing으로 인해 원하는 결과가 아닌 의도치 않은 오류를 도출할 수도 있다는 것을 보았다
이제 또 다른 사례에 대해서 살펴보자

int main()
{
    Derived d1{ 5 };
    Derived d2{ 6 };
    Base& b{ d2 };

    b = d1; // this line is problematic

    return 0;
}

첫 3 라인은 그럴싸 하다
그런데 4번째 라인(b = d1)에서 b가 d2를 가지고 있음으로 d2 = d1 이라고 생각할 수도 있다
하지만 operator= 는 default로 설정된 것에 있어서 virtual이 설정되어 있는 것이 아니기에
결론적으로 d1의 Base portion만이 d2에 복사가 된다

결과적으로 d2는 Base portion은 d1의 그것이고 Derived는 원래 d2의 그것이 합쳐진 결과물이다

우리는 단지 의도치 않은 프랑켄 오브젝트를 만든 것이다

좋은 웹페이지 즐겨찾기