是否有可能每个类只传递一次变量但不能使它变为静态变量?

时间:2015-08-14 04:44:48

标签: c++

这个问题(松散地)与我昨天here提出的问题有关。

我刚刚重构了一个容器类(Ecosystem),其中包含指向Individual的指针:

class Ecosystem
{
    // This is an interface class providing access
    // to functions in Individual without exposing
    // the Individual class.
    // It performs global operations on the entire ecosystem
    // (like sorting individuals based on certain criteria)
    // but is also capable of invoking functions from the
    // Individual class.
    // It also holds the global configuration for this ecosystem.
    private:
        Config config;
        std::map<int, std::shared_ptr<Individual> > individuals;
    public:
        Ecosystem() {};
        void sort_individuals();
        void func1(int _individual_id)
        {
            individuals[_individual_id]->func1(config);
        }

        void func2(int _individual_id)
        {
            individuals[_individual_id]->func2(config);
        }
        // etc...
};

class Individual
{
    private:

    public:
        Individual() {};
        void func1(const Config& _config)
        {
            // Operations using _config.param_1, _config.param_2, ... 
        }

        void func2(const Config& _config)
        {
            // Operations using _config.param_n, _config.param_m, ... 
        }
        // etc...
}

我现在处于这样的情况:我必须通过config几乎每个函数调用Individual个对象。最初我想,好吧,我只是在static Config config;Individual,但很快我意识到我需要能够创建多个具有不同配置的共存生态系统。

如果我正确理解了static的含义,如果我static Config config; Individual内的configEcosystem分配了config,那么每次我创建一个新的生态系统时都会被覆盖。

我的问题是:有没有办法将Config* config 一次传递给个人类,而不会将其设为静态,以避免将其作为参数传递每个功能?

我考虑在EcosystemIndividual中都有const Config config;,但这意味着每个人都会有一个指向配置对象的指针,这似乎很笨拙。我需要的是等效的静态成员,其范围可以识别容器层次结构,如果这有意义的话。

创建后,Config对象不会被更改,因此可以拥有static

提前感谢您的任何建议!

编辑1

感谢大家的回复。 Matthew Kraus指出,我在原始问题中没有为我的生态系统课提供正确的构造函数,这当然是对我的疏忽。我现在看到它可能是相关的,但我更专注于说明我之后的变量访问类型而不是我的类看起来像什么,所以我提出了一个简单的例子。如果我用额外的评论引起讨论混乱,请道歉!

这里提出的解决方案都非常好,但我可以从答案中看出,C ++没有任何方法可以定义这样的类级变量而不将它们定义为class Ecosystem { // This is an interface class providing access // to functions in Individual without exposing // the Individual class. // It performs global operations on the entire ecosystem // (like sorting individuals based on certain criteria) // but is also capable of invoking functions from the // Individual class. // It also holds the global configuration for this ecosystem. private: Config config; std::map<int, std::shared_ptr<Individual> > individuals; public: Ecosystem(const std::string& _file_name) { Config cfg(_file_name); config = cfg; // This is done before any Individual objects are created. Individual::set_config(cfg); for (int i = 1; i <= 10; ++i) { individuals[i] = std::make_shared<Individual>(); } }; void sort_individuals(); void func1(int _individual_id) { individuals[_individual_id]->func1(); } void func2(int _individual_id) { individuals[_individual_id]->func2(); } // etc... }; class Individual { private: // v--- No such thing! scoped static Config config; public: Individual() {}; void func1() { // Operations using config.param_1, config.param_2, ... } void func2() { // Operations using config.param_n, config.param_m, ... } // v--- No such thing! scoped static void set_config(const Config& _config) { config = _config; } // etc... } int main(int argc, char* argv[]) { Ecosystem ecosystem1("config_file1.txt"); Ecosystem ecosystem2("config_file2.txt"); // Conduct experiments with the two ecosytems. // Note that when ecosystem2 is created, the line // // Individual::set_config(cfg); // // should *not* overwrite the class-level variable // config set when ecosystem1 was created. // Instead, it should create a // class-level variable but limited to the scope of ecosystem 2. // This operates on Individual 1 in ecosystem 1 // with the parameters set in config_file1.txt ecosystem1->func1(1); // This operates on Individual 1 in ecosystem 2 // with the parameters set in config_file2.txt ecosystem2->func1(1); return 0; } 。我需要的是一个类级变量,其范围仅限于其容器。这只是我的想法的一个例子,它不会编译(我现在肯定这不能在C ++中完成):

File->settings->Keymap and select 'eclipse' from keymap dropdown.

我将建议在构造时将指针传递给每个人。这会浪费空间,但应该是最容易维护的解决方案。

再次感谢大家的意见,如果问题令人困惑,请道歉。

4 个答案:

答案 0 :(得分:6)

如果我理解正确,将配置传递给Individual的构造函数应该:

class Individual {
    const Config& config_;
public:
    Individual(const Config& c) : config_(c) {}
    void func1() {
        // use config_
    }
};

您仍然需要将Config传递给每个单独的构造函数,但这只是一个单点,而不是Individual会有多少函数。此外,如果您觉得创建过于繁琐,可以将Individual的创建封装到工厂方法中。

答案 1 :(得分:2)

如果Individual个对象不应包含配置,则总是

class ConfiguredIndividualReference
{
private:
    std::shared_ptr<Individal> ptr; // or just Individual* depending on how you use this
    const Config &config;
public:
    // ...
    void func1()
    {
        ptr->func1(config);
    }
    // ...
};

此外,您可以创建一个成员函数来自动生成它:

ConfiguredIndividualReference fetch(int id) const {
    return ConfiguredIndividualReference(individuals[id], config);
}

并且总是使用它来获取个人而不是直接访问地图。

答案 2 :(得分:1)

在我制定解决方案的过程中,有几个答案正在流传,但我还是认为我还是会发布我的答案。这是一个完整的解决方案,可以在上下文中查看所有内容:

#include <iostream>
#include <string>
#include <map>

class Config
{
public:
    explicit Config(std::string name) : name(name) {}

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

private:
    std::string name;
};

class Individual
{
public:
    // using 'explicit' ensures that an Individual is created with a Config
    explicit Individual(const Config& config) :
        config(config) {}

    std::string getConfigName() const { return config.getName(); }

    void func1() {}
    void func2() {}

private:
    // a "const reference" is read-only
    const Config& config;
};

// notice that the dependency on Config is removed from Ecosystem
class Ecosystem
{
    private:
        // std::map<int, std::shared_ptr<Individual> > individuals;
        // I compiled using Individual*, so be aware
        // of the implications of using a naked ptr vs shared_ptr
        std::map<int, Individual*> individuals

    public:
        Ecosystem() {};

        void sort_individuals();
        void func1(int _individual_id)
        {
            // no dependency on Config
            individuals[_individual_id]->func1();
        }

        void func2(int _individual_id)
        {
            individuals[_individual_id]->func2();
        }
};

int main()
{
    using namespace std;

    Config globalConfig("global configuration");
    Config localConfig("local configuration");

    // the Config object passed to an Individual must
    // last the lifetime of the Individual
    Individual individualA(globalConfig);
    Individual individualB(localConfig);

    // the following prints "global configuration"
    cout << "individualA config is: " << individualA.getConfigName() << endl;

    // the following prints "local configuration"
    cout << "individualB config is: " << individualB.getConfigName() << endl;

    return 0;
}

如代码中所述,请确保Config对象超出任何依赖于它的对象。像这样共享对象 - 即使您正在进行const引用 - 删除了物理依赖关系,但它并没有删除逻辑依赖关系。换句话说,C ++编译器可以在不知道Ecosystem的情况下编译Config类。但是,Ecosystem取决于Individual s,而Config依赖于std::shared_ptr s,因此需要预先警告。我的观点是const引用是vanilla C ++的方法,但如果管理Config对象的生命周期是微不足道的话,那么值得考虑shared_ptr

修改

我编译时没有实际使用Individual*;我在地图中使用了<div class="swiper-container" ng-show="menu()"> <div class="swiper-wrapper"> <div class="swiper-slide">Slide 1</div> <div class="swiper-slide">Slide 2</div> <div class="swiper-slide">Slide 3</div> <div class="swiper-slide">Slide 4</div> <div class="swiper-slide">Slide 5</div> <div class="swiper-slide">Slide 6</div> <div class="swiper-slide">Slide 7</div> <div class="swiper-slide">Slide 8</div> <div class="swiper-slide">Slide 9</div> <div class="swiper-slide">Slide 10</div> </div> <!-- Add Pagination --> <div class="swiper-pagination"></div> </div> 。请注意使用一个与另一个的含义。

答案 3 :(得分:1)

我发布了第二个答案,以满足每ConfigEcosystem而不是Individual每个#include <iostream> #include <string> #include <map> class Config { public: explicit Config(std::string name) : name(name) {} std::string getName() const { return name; } private: std::string name; }; class Individual { public: Individual() {} void func1(const Config& config) const { std::cout << config.getName() << std::endl; } // you might remove the dependency of Config and // just pass only the config parameters needed. void func2(Type1 configParam1, Type2 configParam2) {} }; // notice that the dependency on Config is removed from Ecosystem class Ecosystem { public: explicit Ecosystem(Config& config) : config(config) {} void sort_individuals(); void func1(int _individual_id) { individuals[_individual_id]->func1(config); } private: // std::map<int, std::shared_ptr<Individual> > individuals; // I compiled using Individual*, so be aware // of the implications of using a naked ptr vs shared_ptr std::map<int, Individual*> individuals; const Config& config; }; int main() { using namespace std; Config globalConfig("global configuration"); // Config objects don't need to be created in main(); // you could create them on the heap, too: Config* localConfig = new Config("local configuration"); Ecosystem ecosystemA(globalConfig); Ecosystem ecosystemB(*localConfig); // TODO: add Individuals to each Ecosystem // clean up objects on heap delete localConfig; return 0; } 的新要求:

Config

我觉得我们已经回答了OP的原始问题&#34;有没有办法将config一次传递给Individual类而不使其静态,以避免将其作为参数传递每个功能&#34; 。此示例提供了更多选项。

此处的添加是在堆上创建Ecosystem(Config& config)对象。这使得Config的调用者负责管理main()对象。同样,这不必在Config中发生,但您可以修改我的示例以使用智能指针自动管理<ContextMenu.ItemContainerStyle> <Style TargetType="{x:Type MenuItem}"> <Setter Property="IsChecked" Value="{Binding IsCheckedByDefault}"/> <Setter Property="IsCheckable" Value="true"/> <Setter Property="Header" Value="{Binding Title}"/> </Style> </ContextMenu.ItemContainerStyle> 个对象的生命周期。