1

より効果的な C++項目 3: 配列をポリモーフィックに扱うことはありません に基づいて、配列をポリモーフィックに扱うことは避ける必要があります。

では、なぜstd::vector基底クラスを指すポインターを問題なく保持できるのでしょうか?

ありがとうございました

#include <iostream>
#include "boost/shared_ptr.hpp"
#include <vector>

class BaseClass {
public:
    virtual void PrintMe() const {
        std::cout << "BaseClass" << std::endl;
    }
    virtual ~BaseClass() {}
};

class SubClass : public BaseClass {
public:
    virtual void PrintMe() const {
        std::cout << "SubClass" << std::endl;
    }
};

int main()
{
    std::vector<boost::shared_ptr<BaseClass> > vecPtrs;
    boost::shared_ptr<BaseClass> shp1(new BaseClass);
    vecPtrs.push_back(shp1);

    boost::shared_ptr<BaseClass> shp2(new SubClass);
    vecPtrs.push_back(shp2);

    for (size_t i = 0; i < vecPtrs.size(); ++i)
    {
        vecPtrs[i]->PrintMe();
    }
}

// Output:

BaseClass
SubClass
Press any key to continue . . .
4

4 に答える 4

10

多相型へのポインターを保持するために、配列またはベクターのいずれかを使用しても問題ありません。

問題は、オブジェクトの配列をポリモーフィックに処理しようとした場合です。ポインターを介した配列アクセスでは、ポインターの型を使用して配列オブジェクトのサイズを決定します。ポインターの型がオブジェクトの型と一致しない場合、これはひどくうまくいきません。

Base * stuff = new Derived[10]; // No compile error: pointer conversion is allowed
stuff[2].do_something();        // Still no compile error, but weird runtime errors.
于 2013-02-19T17:45:10.593 に答える
2

問題はこれです:

struct base {
    int element;
};

struct derived : base {
    int another_element;
};

void f(base *p) {
    std::cout << (void*)&p[1] << '\n';
}

int main() {
    derived array[20];
    std::cout << (void*)&array[1] << '\n';
    f(array);
    return 0;
}

このプログラムを実行すると、配列のインデックス 1 の要素に対して2 つの異なるアドレスが取得されます。

これは、 への呼び出しの時点でf、名前arrayがその最初の要素へのポインターに崩壊するために発生します。それはderived*であり、コンパイラはそのポインタを に変換base*してに渡しfます。内部fでは、ポインター演算は渡されたポインターを として扱いますbase*p[1]は、アドレスがsizeof(base)より上のバイトであるオブジェクトを指します。つまり、配列内pの最初のオブジェクトの中央を指します。derived

したがって、最初の要素以外の配列要素で何をしても意味がありません。

于 2013-02-19T18:07:04.110 に答える
2

について魔法は何もありませんstd::vector。基本クラスへのポインターを保持する通常の配列は、まったく同じように機能します。

于 2013-02-19T17:43:24.167 に答える
1

これを行うべきではないと言っています:

Base array[N];
array[0] = Derived1();
array[1] = Derived2();

これらの派生オブジェクトは、配列に配置されるときにスライスされます。

のような標準コンテナの場合もまったく同じですstd::vector。C++ でポリモーフィックな動作を行うには、ポインターを使用する必要があります。

std::unique_ptr<Base> array[N];
array[0].reset(new Derived1());
array[1].reset(new Derived2());
于 2013-02-19T17:46:19.610 に答える