繁体   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