推荐的在C ++中实现双向可见性的方法

时间:2018-02-20 20:21:19

标签: inheritance constructor reference c++14 smart-pointers

我想知道这个推荐的方式是什么,我认为在C ++ 14中类实例及其成员之间的双向可见性。

作为一个例子,我们假设我想写一个由不同类型的人填充的 World 类。所以世界拥有std :: vector>。 Person应该是一个抽象基类,在 PersonOne PersonTwo 中实现纯虚函数。现在我想让人员实例能够访问他们的世界,包括其他人。

我的第一种方法是将世界作为引用传递给世界构造函数中的 this 。但是,我不确定这是否会让我陷入困境。理想情况下,我想拥有这个自包含的,即包含内部人的世界应该在世界的构造函数中完全初始化,并且应该可以复制 - 构建一个世界而不需要单独调整人的属性。智能指针似乎不是一个可行的选择,因为我无法在世界的构造函数中创建一个shared_ptr并将其传递给他们的人员。

class Person{
    public:
    World &world;

    Person(World &_w):world(_w){};
};

class PersonOne: public Person{

    public: 
    PersonOne(World &_w):Person(_w);
};

class PersonTwo: public Person{

    public: 
    PersonTwo(World &_w):Person(_w){};

};

class World{
    public:
    std::vector<std::unique_ptr<Person>> people;

    World(){
        people.push_back(std::make_unique<PersonOne>(*this));
        people.push_back(std::make_unique<PersonTwo>(*this));
    }; 
};

1 个答案:

答案 0 :(得分:1)

在这种情况下复制很棘手,因为您始终必须确保TextView myText; String appName; String helloWord; String txt; myText = findViewById (R.id.mytext); appName = getResources().getString(R.string.app_name); helloWord = getResources().getString(R.string.helloWord); txt = myText.getText().toString(); public void changeText(View v){ if (txt.equals(helloWord)){ myText.setText(appName); }else if(txt.equals(appName)){ myText.setText(helloWord); } } 引用右Person。一种选择是确保在World中有自定义复制构造函数和operator=,您可以在其中调用函数来更新填充。像这样:

World

打印

#include <iostream>
#include <vector>
#include <string>
#include <functional>

using uint = unsigned int;

class World;
using WorldRef = std::reference_wrapper<World>;

class Person
{
    WorldRef world;
    std::string name;
    friend class World;
public:

    Person(World& _world,
           const std::string& _name)
        :
          world(_world),
          name(_name)
    {}
};

class World
{
    uint year;
    std::string name;
    std::vector<Person> population;
    friend class Person;

    void init()
    {
        for (auto& p : population)
        {
            /// Note: This is necessary, otherwise this world's
            /// inhabitants will refer to the wrong world.
            /// Call this function from each constructor and
            /// assignment operator.
            p.world = std::ref(*this);
        }
    }

public:

    World(const uint _year,
          const World& _other,
          const std::string& _name)
        :
          year(_year),
          population(_other.population),
          name(_name)
    {
        init();
        std::cout << "It is now " << year << "\n"
                  << "Melon Tusk has built a rocket allowing cheap interplanetary travel.\n";
        for (auto& p : population)
        {
            std::cout << p.name << " has moved to " << p.world.get().name << "\n";
        }
    }

    World(const uint _year,
          const std::string& _name,
          const uint _pop_size)
        :
          year(_year),
          name(_name),
          population(_pop_size, {*this, "Anonymous " + _name + "ling"})
    {
        init();
        std::cout << "It is " << year << "\n";
        std::cout << name << " has " << population.size() << " inhabitants:\n";
        for (const auto& p : population)
        {
            std::cout << p.name << "\n";
        }
    }

    void operator = (const World& _other)
    {
        population = _other.population;
        init();
    }

    void set_name(const std::string& _name)
    {
        name = _name;
    }

    std::string get_name() const
    {
        return name;
    }

    void add_person(const std::string& _name)
    {
        population.emplace_back(*this, _name);

        std::cout <<_name << " was born on " << name << "\n";
    }

    uint population_size() const
    {
        return population.size();
    }
};

int main()
{
    World earth(2018, "Earth", 5);
    World mars(2025, earth, "Mars");

    mars.add_person("Alice");
    mars.add_person("Bob");
    mars.add_person("Carol");

    World europa = mars;
    europa.set_name("Europa");

    std::cout << "Everyone has moved on to " << europa.get_name() << "\n";

    europa.add_person("David");

    std::cout << europa.get_name() << " has a population of " << europa.population_size() << "\n"
              << "A war is brewing over scant resources.\n"
              << "Such is the nature of humanity.\n";

    return 0;
}

请注意我们如何在每个构造函数和It is 2018 Earth has 5 inhabitants: Anonymous Earthling Anonymous Earthling Anonymous Earthling Anonymous Earthling Anonymous Earthling It is now 2025 Melon Tusk has built a rocket allowing cheap interplanetary travel. Anonymous Earthling has moved to Mars Anonymous Earthling has moved to Mars Anonymous Earthling has moved to Mars Anonymous Earthling has moved to Mars Anonymous Earthling has moved to Mars Alice was born on Mars Bob was born on Mars Carol was born on Mars Everyone has moved on to Europa David was born on Europa Europa has a population of 9 A war is brewing over scant resources. Such is the nature of humanity. 中调用init()。根据您的需要,可能有一种更简洁的方法。

P.S。我不确定从逻辑角度来看复制一个operator=对象意味着什么,因为你最终会得到World的克隆。也许这正是你想要的,但我只是想提到它。