暗黙的な型変換によるオブジェクトのスライス

実引数として渡される C++ オブジェクトが暗黙的な型変換によってスライスされます。

例えば、myBase というクラスとその派生クラス myDerived について考えてみます。myDerived には、myBase のすべてのデータメンバーと myDerived 固有のものが含まれています。C++ では、myDerived のインスタンスを myBase のインスタンスに代入できます。その際に、myDerived 固有のデータメンバーは "スライス" されます。スライスと通常の多相性は異なります。多相性は、myDerived へのポインターが myBase へのポインターに代入された場合に発生します。

継承されたデータメンバーのデータの整合性が、派生クラス (myDerived) で保持されるかどうか保証されていないため、スライスは危険です。つまり、すべてのオブジェクトが安全にスライスできるわけではありません。以下の例は、安全でないスライスです。

C++ は、関数呼び出しで暗黙的にスライスを実行します。例えば、myDerived のインスタンスが myBase を想定した関数に渡されると、myDerived はスライスされます。これは、オブジェクトが値渡しのために発生します。スライスは、オブジェクトを参照渡しにすることで回避できます。

ID

問題箇所

説明

1

呼び出し位置

スライスが発生した場所


#include <string.h>
#include <stdlib.h>
#include <stdio.h>

class myBase {
protected:
    char * m_a;
public:
    explicit myBase(char * contents) {
        int size = strlen(contents) + 1;
        m_a = (char *)malloc(size);
        strcpy_s(m_a, size, contents);
    }

    virtual ~myBase() { free(m_a); }

    virtual void print_me(void) {
       if (m_a == 0) {
           printf("I am invalid\n");
       } else {
           printf("I am %s\n", m_a);
       }
    }
};

class myDerived : public myBase {
    char m_b[10];
public:
    explicit myDerived(char * contents) : myBase(contents) {
        // myDerived caches m_a, thus making myDerived unfit to slice
        if (strlen(m_a) < 10) {
            strcpy_s(m_b, sizeof(m_b), m_a);
            free(m_a);
            m_a = 0;
        }
    }
    void print_me(void) {
        printf("I am %s\n", m_b);
    }
};

void expects_an_A(myBase parm) {
    parm.print_me(); // prints I am invalid
}

int main(int argc, char **argv)
{
    myDerived b("good");
    myBase *pa = &b;  // polymorphism, not slicing
    myBase a = b;         // b is sliced here
    pa->print_me();  // prints I am good
    b.print_me();    // prints I am good
    a.print_me();    // prints I am invalid
    expects_an_A(b); // b is also sliced here
    return 0;
}
        

© 2010 Intel Corporation. 無断での引用、転載を禁じます。