簡體   English   中英

在C ++中存儲具有相同基類的對象 <vector> 按值(無指針)通過刪除復制構造函數等

[英]Store objects with the same base class in C++ <vector> by value (no pointers) by deleting the copy constructor etc

我已經閱讀(這里https://stackoverflow.com/a/18351550/1474291 ),可以在<vector>存儲繼承相同基類的派生類的對象。 為了防止對象切片,我需要刪除move構造函數,copy構造函數和copy分配。

注意:我有興趣按值而不是指針存儲對象。

我嘗試使用Visual C ++ 2013和MinGW(GCC 4.8.2和4.9.1)編譯以下代碼,但是代碼無法編譯。 我想在C ++ 11中通過使用“刪除”,“默認”和較舊的方式來做到這一點。

正確的實現方式是什么? (實際上,C ++編譯器是否還正確支持“刪除”和“默認”?)

這是我的示例代碼:

#include <iostream>
#include <vector>

using namespace std;

#if __cplusplus > 199711L
    #define CPP11
#endif


class Animal {
public:
    Animal() {
        cout << "Making animal:";
    }
    virtual ~Animal() {
        cout << "Send the animal home!";
    }

#ifdef CPP11
public:
    Animal(Animal&&) = delete;
    Animal(Animal const&) = delete;
    Animal& operator=(Animal&) = delete;
#else // C++98
private:
    Animal(Animal const&);
    Animal& operator=(Animal&);
#endif // CPP11

public:
    virtual void speak() {
        cout << "I am an animal!";
    }
};

class Dog : public Animal {
public:
    Dog() {
        cout << "Making dog:";
    }

    virtual ~Dog() {
        cout << "Send the dog home!";
    }

#ifdef CPP11
public:
    Dog(Dog&&) = default;
    Dog(Dog const&) = default;
    Dog& operator=(Dog&) = default;
#else // C++98
private:
    Dog(Dog const&);
    Dog& operator=(Dog&);
#endif // CPP11

    virtual void speak() {
        cout << "I am a dog!";
    }
};

class Cat : public Animal{
public:
    Cat() {
        cout << "Making cat";
    }

    virtual ~Cat() {
        cout << "Sending the cat home!";
    }

#ifdef CPP11
public:
    Cat(Cat&&) = default;
    Cat(Cat const&) = default;
    Cat& operator=(Cat&) = default;
#else // C++98
private:
    Cat(Cat const&);
    Cat& operator=(Cat&);
#endif // CPP11

    virtual void speak() {
        cout << "I am a cag!";
    }
};

int main()
{
    vector<Animal> animals;

    for (int i = 0; 10 > i; i++) {
        Dog dog;
        animals.push_back(dog);
        Cat cat;
        animals.push_back(cat);
    }

#ifdef CPP11
    for (Animal& animal: animals) {
        animal.speak();
    }
#else
    for (std::vector<Animal>::iterator currentAnimal = animals.begin();
         currentAnimal != animals.end();
         ++currentAnimal) {
        currentAnimal->speak();
    }

#endif // CPP11

    return 0;
}

我想您缺少的一點是,容器需要為它包含的每個元素留出一定數量的內存。 因此,容器的元素大小固定

現在,您要將不同大小的對象填充到那些固定大小的框中。 您看到這里的方向了嗎?

每當您嘗試將大於其基類的派生對象填充到旨在容納基類大小的對象的變量(讀取容器元素)中時,就會得到切片。

將派生類型的對象放入基礎向量中時,無法避免對象切片。 您所參考的問題說明了如何通過使其無法復制相關類型的對象來避免對象切片。 這意味着您會得到編譯錯誤,而不是對象切片。

除此之外,一種實現可以通過值存儲的“多態”類型的可能方法是實現一個單一類型,該類型的實現可以在運行時設置。 遵循以下原則:

class Animal
{
 public:
  void talk() const { impl_->talk(); }
  // implement copy, assignment, move copy, move assignment
  // implement constructor allowing to specify the implementation

 private:
  std::unique_ptr<AnimalImpl> impl_;
};

struct AnimalImpl
{
  virtual void talk() const = 0;
  virtual ~AninalImpl() {}
};

struct Elephant : AnimalImpl
{
  void talk() const override { std::cout << "I am an elephant\n"; }
};

然后,您提供了一種使用不同的基礎實現構造Animal對象的方法。 這允許你不同種存儲Animalstd::vector<Animal>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM