C++ C++;朋友子类访问私有成员(策略模式)

C++ C++;朋友子类访问私有成员(策略模式),c++,inheritance,design-patterns,friend,C++,Inheritance,Design Patterns,Friend,我已经为遗传算法编写了一个交叉方法(参见) 交叉方法修改了染色体类的私有成员,但我将其从染色体中拉出来,放入一个单独的纯虚拟基类CrossoverStrategy(染色体之友),以使每个交叉方法都很好地封装在一个子类中,即GoF策略模式(请参阅) 现在问题是交叉策略子类不能访问染色体私有成员,因为友谊不是C++继承的。我看到的唯一两种解决方案是: 1) 将访问器方法添加到纯虚拟基类,例如CrossoverStrategy::getGenes()以使子类可以访问染色体私有成员。因为Crossove

我已经为遗传算法编写了一个交叉方法(参见)

交叉方法修改了染色体类的私有成员,但我将其从染色体中拉出来,放入一个单独的纯虚拟基类CrossoverStrategy(染色体之友),以使每个交叉方法都很好地封装在一个子类中,即GoF策略模式(请参阅)

现在问题是交叉策略子类不能访问染色体私有成员,因为友谊不是C++继承的。我看到的唯一两种解决方案是:

1) 将访问器方法添加到纯虚拟基类,例如CrossoverStrategy::getGenes()以使子类可以访问染色体私有成员。因为CrossoverStrategy无法预测它的子类可能希望与染色体相关的所有内容,所以我需要提前公开所有内容。丑

2) 向前声明每个CrossoverStrategy子类,并显式地使其成为染色体的朋友。这感觉稍微不那么难看,至少保持了界面和代码的整洁。我倾向于这种美学选择

还有更好的设计建议吗?代码如下

// Chromosome.h ++++++++++++++++++++++++++++++++++++++++++++++++

class CrossoverStrategy
{
public:
    virtual std::vector<Chromosome*> crossover(Chromosome *parent1, Chromosome *parent2) = 0;
    const std::vector<double> &getGenes(Chromosome *instance) { return instance != NULL ? instance->m_genes : std::vector<double>(); }; // OPTION #1 ... BOO! UGLY!
};

class CrossoverStrategyExample1; // OPTION #2 ... BOO! UGLY!

class Chromosome
{
public:
    // Friends
    friend class CrossoverStrategy;
    friend class CrossoverStrategyExample1; // OPTION #2 ... BOO! UGLY!
private:
    std::vector<double> m_genes;
};

// CrossoverStrategies.h ++++++++++++++++++++++++++++++++++++++++++++++++

#include "Chromosome.h"

class CrossoverStrategyExample1 : public CrossoverStrategy
{
public:
    virtual std::vector<Chromosome*> crossover(Chromosome *parent1, Chromosome *parent2);
private:
};

// CrossoverStrategies.cpp ++++++++++++++++++++++++++++++++++++++++++++++++

#include "CrossoverStrategies.h"

std::vector<Chromosome*> CrossoverStrategyExample1::crossover(Chromosome *parent1, Chromosome *parent2)
{
    // Do something with Chromosome private members
    // PROBLEM ... m_genes not accessible to subclasses? BOO BOO BOO!
    (for unsigned long i = 0; i < parent1->m_genes.size(); i++)
        parent1->m_genes[i] = 0.0;
}
//chromose.h++++++++++++++++++++++++++++++++++++++++++++++++
阶级交叉战略
{
公众:
虚拟性病::载体交叉(染色体*parent1,染色体*parent2)=0;
const std::vector&getGenes(chromose*instance){return instance!=NULL?instance->m_genes:std::vector()};//选项#1…BOO!丑陋!
};
类交叉超越策略示例1;//选项2。。。喝倒采丑!
类染色体
{
公众:
//朋友
友邦战略;
friend类CrossoverStrategyExample1;//选项#2…呸!丑陋!
私人:
std::载体m_基因;
};
//交叉战略++++++++++++++++++++++++++++++++++++++++++++++++
#包括“染色体h”
类交叉策略示例1:公共交叉策略
{
公众:
虚拟性病::载体交叉(染色体*parent1,染色体*parent2);
私人:
};
//交叉策略++++++++++++++++++++++++++++++++++++++++++++++++
#包括“CrossoverStrategies.h”
std::vector CrossoverStrategyExample1::交叉(染色体*parent1,染色体*parent2)
{
//对私人成员做些什么
//问题…子类无法访问m_基因?嘘嘘嘘!
(对于无符号长i=0;im_genes.size();i++)
parent1->m_基因[i]=0.0;
}

应拒绝选项2,因为它不可缩放。您将不断修改
染色体
,使其与新的
交叉策略
保持最新

选项1是一个奇怪的想法,因为它将
染色体
的数据成员的getter函数放在
染色体
之外。如果
getGenes
受到保护,我可以看到一些情况下这是一个很有吸引力的想法,但我在这里并不确信。而不是考虑< /P> 备选案文1-A 交叉战略++++++++++++++++++++++++++++++++++++++++++++++++

#include <vector>
class Chromosome; // forward declaration only
class CrossoverStrategy
{
public:
    virtual ~CrossoverStrategy() = default;
    virtual std::vector<Chromosome*> crossover(Chromosome *parent1, Chromosome *parent2) = 0;
};

Chromosome * ChromosomeFactory(/* some construction parameters here */);
// should also provide a declaration of a factory function to provide CrossoverStrategies
#include "Chromosome.h"

class CrossoverStrategyExample1 : public CrossoverStrategy
{
public:
    virtual std::vector<Chromosome*> crossover(Chromosome *parent1, Chromosome *parent2);
private:
};
#include "CrossoverStrategies.h"
class Chromosome
{
public:
    std::vector<double> m_genes;

    // silence a warning
    Chromosome(): m_genes{}
    {

    }
};

// Because Chromosome is only defined in this file, only this file can use the internals 
// of Chromosome. They are public, but the outside world doesn't know that 

Chromosome * ChromosomeFactory(/* some construction parameters here */)
{
    // Probably makes and returns a pointer to a Chromosome,
    // but could pull it from a list, copy construct from a template, etc...
    return new Chromosome(/* some construction parameters here */);
}

// should also provide a definition of a factory function to provide CrossoverStrategies


std::vector<Chromosome*> CrossoverStrategyExample1::crossover(Chromosome *parent1,
                                                              Chromosome *parent2)
{
    for (unsigned long i = 0; i < parent1->m_genes.size(); i++)
        parent1->m_genes[i] = 0.0;
    return std::vector<Chromosome*>{}; // silence a warning
}
#include "Chromosome.h"
#include "CrossoverStrategies.h" // A bad idea. Forces recompilation when strategies are added

int main()
{
    Chromosome * p1 = ChromosomeFactory(/* some construction parameters here */);
    p1->m_genes.push_back(0.0); // will fail to compile (incomplete type)
    Chromosome * p2 = ChromosomeFactory(/* some construction parameters here */);
    
    // probably should hide the next line with a factory as well
    CrossoverStrategy * strategy = new CrossoverStrategyExample1();
    strategy->crossover(p1, p2);
}

关于安全问题的简短后记。它总是要付出代价的。一般来说,它使东西更难使用。这让攻击者更难对付,但也让合法用户更难对付。它是否值得由您决定。

选项2应该被拒绝,因为它不可扩展。您将不断修改
染色体
,使其与新的
交叉策略
保持最新

选项1是一个奇怪的想法,因为它将
染色体
的数据成员的getter函数放在
染色体
之外。如果
getGenes
受到保护,我可以看到一些情况下这是一个很有吸引力的想法,但我在这里并不确信。而不是考虑< /P> 备选案文1-A 交叉战略++++++++++++++++++++++++++++++++++++++++++++++++

#include <vector>
class Chromosome; // forward declaration only
class CrossoverStrategy
{
public:
    virtual ~CrossoverStrategy() = default;
    virtual std::vector<Chromosome*> crossover(Chromosome *parent1, Chromosome *parent2) = 0;
};

Chromosome * ChromosomeFactory(/* some construction parameters here */);
// should also provide a declaration of a factory function to provide CrossoverStrategies
#include "Chromosome.h"

class CrossoverStrategyExample1 : public CrossoverStrategy
{
public:
    virtual std::vector<Chromosome*> crossover(Chromosome *parent1, Chromosome *parent2);
private:
};
#include "CrossoverStrategies.h"
class Chromosome
{
public:
    std::vector<double> m_genes;

    // silence a warning
    Chromosome(): m_genes{}
    {

    }
};

// Because Chromosome is only defined in this file, only this file can use the internals 
// of Chromosome. They are public, but the outside world doesn't know that 

Chromosome * ChromosomeFactory(/* some construction parameters here */)
{
    // Probably makes and returns a pointer to a Chromosome,
    // but could pull it from a list, copy construct from a template, etc...
    return new Chromosome(/* some construction parameters here */);
}

// should also provide a definition of a factory function to provide CrossoverStrategies


std::vector<Chromosome*> CrossoverStrategyExample1::crossover(Chromosome *parent1,
                                                              Chromosome *parent2)
{
    for (unsigned long i = 0; i < parent1->m_genes.size(); i++)
        parent1->m_genes[i] = 0.0;
    return std::vector<Chromosome*>{}; // silence a warning
}
#include "Chromosome.h"
#include "CrossoverStrategies.h" // A bad idea. Forces recompilation when strategies are added

int main()
{
    Chromosome * p1 = ChromosomeFactory(/* some construction parameters here */);
    p1->m_genes.push_back(0.0); // will fail to compile (incomplete type)
    Chromosome * p2 = ChromosomeFactory(/* some construction parameters here */);
    
    // probably should hide the next line with a factory as well
    CrossoverStrategy * strategy = new CrossoverStrategyExample1();
    strategy->crossover(p1, p2);
}

关于安全问题的简短后记。它总是要付出代价的。一般来说,它使东西更难使用。这让攻击者更难对付,但也让合法用户更难对付。它是否值得,取决于你。

< P>第一个明显的选项是考虑<代码>染色体< /代码>的成员是否应该或不应该是代码>公共< /代码>。鉴于您希望任意数量的类访问其数据,一个明显的选择是将该数据
公开

第二个选项是为
染色体
提供受影响数据的公共getter和setter,例如

 class Chromosome
 {
      public:

          std::vector<double> getGenes() const {return m_genes;};
          bool setGenes(const std::vector<double> &newgenes)
          {
               bool is_error = true;
               if (IsValid(newgnes))
               {
                    is_error = false;
                    m_genes = newgenes;
               }
               return is_error;    //  return true if change is rejected
          };

       private:

           std::vector<double> m_genes;
 };

这样,只有从
CrossOverStrategy
派生的类才能访问
受保护的
帮助程序。如果
染色体
的工作方式发生变化,那么在这种情况下需要调整的唯一类就是基本
交叉策略
类,因为其派生类根本不(直接)访问
染色体
,选项是考虑<代码>染色体< /代码>的成员是否应该或不应该是<代码>公共< /代码>。鉴于您希望任意数量的类访问其数据,一个明显的选择是将该数据
公开

第二个选项是为
染色体
提供受影响数据的公共getter和setter,例如

 class Chromosome
 {
      public:

          std::vector<double> getGenes() const {return m_genes;};
          bool setGenes(const std::vector<double> &newgenes)
          {
               bool is_error = true;
               if (IsValid(newgnes))
               {
                    is_error = false;
                    m_genes = newgenes;
               }
               return is_error;    //  return true if change is rejected
          };

       private:

           std::vector<double> m_genes;
 };

这样,只有从
CrossOverStrategy
派生的类才能访问
受保护的
帮助程序。如果
染色体
的工作方式发生了变化,那么在这种情况下,唯一需要调整的类就是基本
交叉策略
类——因为它的派生类根本不(直接)访问
染色体

你的想法根本就有缺陷

一方面,你说你不想让任何人搞乱基因载体

另一方面,你希望任何
交叉策略的后代都能搞乱基因载体

但有一个矛盾。一个阶级的“任何后裔”就是“任何人”。任何