7

// Cat.h

class Cat
{public:
    void const_meow() const{ ... };
    void meow(){ ... };
};

class CatLibrary
{public:
    std::vector<std::shared_ptr<Cat>>::iterator begin()
    { 
        return m_cat_list.begin();
    }

    // compile error, the compiler complains cannot covert type
    //     from `std::vector<std::shared_ptr<Cat>>::const_iterator` 
    //     to   `std::vector<std::shared_ptr<const Cat>>::const_iterator`
    std::vector<std::shared_ptr<const Cat>>::const_iterator begin() const 
    { 
        return m_cat_list.cbegin();
    }
private:
    std::vector<std::shared_ptr<Cat>> m_cat_list;
};

// main.cpp

CatLibrary cat_library;       
cat_library.add(std::make_shared<Cat>());
cat_library.add(std::make_shared<Cat>());

for(auto& cat: cat_library )
{
   cat->const_meow(); 
   cat->meow(); 
}       
for(const auto& cat: cat_library)
{
   cat->const_meow(); 
   cat->meow();       // hope to compile error due to invoking non_const method of Cat.
}


const CatLibrary& const_cat_library = cat_library;        
for(auto& cat: const_cat_library ) 
{
   cat->const_meow(); 
   cat->meow();       // hope to compile error due to invoking non_const method of Cat.
}
const CatLibrary& const_cat_library = cat_library; 

for(const auto& cat: const_cat_library ) 
{
   cat->const_meow(); 
   cat->meow();       // hope to compile error due to invoking non_const method of Cat.
}

CatLibraryで、クライアントが変更可能な Cat を指すスマート ポインターを反復できるnon-const begin()andを公開したいと考えています。non-const end()そして、不変のものを指すイテレータconst begin()const end()返します。

次に、クライアントが const CatLibrary を反復するとき、ライブラリ内の Cat の内容を変更できることを心配する必要はありません。

しかし、const追加されたメンバー関数begin()は、ポインターが指す Cat ではなく、ポインターを const ポインターとして修飾するだけです。

ポインターが含まれていない場合、constness を持つベクトルは、反復子が constness を持つ要素を指すようにします。しかし、私はこの効果がスマートポインタが指す要素にも適用されることを望んでいます。

問題を解決するためのアプローチがありますが、将来の使用でどのような問題が発生するかわかりません。

const と nonconst で 2 つのベクトルを維持する

#include <iostream>
#include <memory>
#include <vector>

class Cat
{public:
    void const_meow() const { std::cout << "meow" << std::endl;}
    void meow() { std::cout << "meow" << std::endl;}
};


class CatLibrary
{public:

    void add(std::shared_ptr<Cat> cat)
    {
        m_cat_list.push_back(cat);
        m_cat_const_list.push_back(cat);
    };

    std::vector<std::shared_ptr<Cat>>::const_iterator begin()
    { 
        return m_cat_list.begin();
    }

    std::vector<std::shared_ptr<const Cat>>::const_iterator begin() const
    { 
        return m_cat_const_list.begin();
    }

    std::vector<std::shared_ptr<Cat>>::const_iterator end()
    { 
        return m_cat_list.end();
    }

    std::vector<std::shared_ptr<const Cat>>::const_iterator end() const
    { 
        return m_cat_const_list.end();
    }


private:
    std::vector<std::shared_ptr<Cat>> m_cat_list;
    std::vector<std::shared_ptr<const Cat>> m_cat_const_list;
};


int main()
{
   CatLibrary cat_library;

   cat_library.add(std::make_shared<Cat>());
   cat_library.add(std::make_shared<Cat>());
   cat_library.add(std::make_shared<Cat>());

   const CatLibrary& const_cat_library = cat_library;
   for(auto& cat: cat_library)
   {
      cat->meow();
   }

   return 0;
}

または、この種の constness の問題をベクトルのスマート ポインターで解決する別の解決策はありますか?

4

3 に答える 3

1

投稿した例では、begin() と end() の const バージョンは必要ありません。これらの関数の const バージョンがなくても、範囲ベースの for ループで const 参照を使用でき、const メンバー関数を呼び出すために cat を const auto& にする必要はまったくありません。

cat_library オブジェクト自体が const である場合、const begin() および end() が必要になる場合がありますが、そのような項目を追加することはできません。

于 2014-08-06T07:54:29.387 に答える
0

私は実際にあなたの抽象化を変えて、あなたの猫のコレクションをカプセル化することを検討したいと思います. イテレータと可変オブジェクトは実装の詳細です。

したがって、代わりに cat で関数を記述します。

PrintCats()
PlayWithCats()

あなたの猫のライブラリが、実行したい操作を認識していない場合は、関数ポインターを渡すことを検討できます。boost::function はこれに適しています。あなたは次のような機能を持っているでしょう

void CatLibrary::DoStuffToCats(boost::function<void, (const Cat&)> f))
{
    std::foreach(m_cat_list.begin(), m_cat_list.end(), f);
}
于 2014-08-06T10:29:32.863 に答える