繁体   English   中英

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

[英]Is it possible to pass a variable only once per class but not make it static?

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

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

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; 在从Ecosystem分配config值的Individual ,每次创建新生态系统时都会被覆盖。

我的问题是:有没有办法将config 一次传递给Individual类而不使其为静态 ,以避免将其作为参数传递给每个函数?

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

一旦创建,Config对象将不会被更改,因此可以有一个const Config config;

提前感谢您的任何建议!


编辑1

谢谢大家的回复。 马修克劳斯有一个观点,我在原始问题中没有提供我的生态系统类的正确构造函数,当然,这是对我的疏忽。 我现在看到它可能是相关的,但我更专注于说明我所追求的变量访问类型而不是我的类的外观,所以我提出了一个简单的例子。 如果我用额外的评论引起讨论的混乱,我会道歉!

这里提出的解决方案都非常好,但我可以从答案中看出,C ++没有任何方法来定义这样的类级变量而不将它们定义为static 我需要的是一个类级变量,其范围仅限于其容器。 这只是我的想法的一个例子,它不会编译(我现在肯定这不能在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;
}

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

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

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

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

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

如果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);
}

并始终使用此来获取个人而不是直接访问地图。

我正在研究一个解决方案时,有几个答案在流淌,但我想我还是会发布我的答案。 这是一个完整的解决方案,可以查看上下文中的所

#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 ++编译器可以在不知道Config情况下编译Ecosystem类。 然而, Ecosystem依赖于Individual ,而Individual依赖于Config ,因此需要预先警告。 我的观点是const引用是vanilla C ++的方法,但是如果管理Config对象的生命周期是微不足道的话,可能值得考虑std::shared_ptr

编辑

我在编译时没有实际使用shared_ptr ; 我在地图中使用了Individual* 请注意使用一个与另一个的含义。

我张贴第二个答案,以满足只有一新的要求Config每个Ecosystem ,而不是每一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;
}

我觉得我们已经回答了OP的原始问题“是否有一种方法可以将配置文件一次传递给Individual类,而不会将其设置为静态,以避免将其作为每个函数的参数传递” 此示例提供了更多选项。

这里的添加是在堆上创建Config对象。 这使得Ecosystem(Config& config)的调用者负责管理Config对象。 同样,这不一定发生在main() ,但您可以修改我的示例以使用智能指针自动管理Config对象的生命周期。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM