C++ 在C+中实现复杂继承+;

C++ 在C+中实现复杂继承+;,c++,inheritance,C++,Inheritance,我现有以下课程: class Gaussian { public: virtual Vector get_mean() = 0; virtual Matrix get_covariance() = 0; virtual double calculate_likelihood(Vector &data) = 0; }; class Diagonal_Gaussian : public Gaussian { public: virtual Vector get_mean()

我现有以下课程:

class Gaussian {
public:
  virtual Vector get_mean() = 0;
  virtual Matrix get_covariance() = 0;
  virtual double calculate_likelihood(Vector &data) = 0;
};

class Diagonal_Gaussian : public Gaussian {
public:
  virtual Vector get_mean();
  virtual Matrix get_covariance();
  virtual double calculate_likelihood(Vector &data);
private:
  Vector m_mean;
  Vector m_covariance;
};

class FullCov_Gaussian : public Gaussian {
public:
  virtual Vector get_mean();
  virtual Matrix get_covariance();
  virtual double calculate_likelihood(Vector &data);
private:
  Vector m_mean;
  Matrix m_covariance;
};
如您所见,Gaussian类充当接口,但没有任何实现。这一切都很好

现在我想创建一个类“AdaptedGaussian”,在这个类中,在计算似然度之前,提供给计算似然度的数据向量将被更改

一些要求:

  • AdaptedGaussian必须是Gaussian的子类
  • AdaptedGaussian必须能够“包装”或“成为”每个可能的高斯类的实例
  • AdaptedGaussian必须从已存在的高斯对象构造
我现在的想法是:

class Adapted_Gaussian : public Gaussian {
private:
  Gaussian* m_g;

public:
  virtual Vector get_mean() { return m_g->get_mean(); }
  virtual Matrix get_covariance() { return m_g->get_covariance(); }
  virtual double calculate_likelihood(Vector &data) 
  { 
    //do something with data
    return g->calculate_likelihood(Vector &data); 
  }
} 
可能有一些缺点:

  • 对于每个方法(这里还有更多的方法),必须在新类中编写一个伪方法
  • 如果高斯函数被扩展,这个类就会被遗忘,那么讨厌的bug就会出现
我这样做对吗?还是有更好的方法来实现这一点


是否有一种好方法可以标准地将每个未实现的方法委托给m_g的同一个命名方法?

看起来不错,我认为这是适配器模式的一个非常经典的实现。只是别忘了为高斯类声明一个虚拟析构函数。至于缺点

  • Java类库处理伪方法问题的方法是创建一个伪类,为每个方法提供空的实现。所有不想实现每个方法的类都可以从这个伪类继承,并有选择地重写它们感兴趣的方法
  • 如果用几个方法扩展Gaussian类,只要将它们声明为纯虚拟方法,子类文件中就会出现编译器错误

  • 在Java中,通常都有一个接口和一个抽象类来实现它,从而为所有方法提供默认行为。(请参阅Joshua Bloch在java.util包中设计的Collections API。)也许这也能对您有所帮助。您将为客户端提供使用接口或抽象类的选择


    你也可以试试。将一个已调整的高斯函数的实例传递给子类,并将行为延迟给它。

    这也可以通过一个

    对我来说,达菲莫也在用“构图”朝着这个方向思考。以这种方式更改设计,即基类调用它所包含的其他对象的某个方法。此对象包含用于计算概率的编码。要么推迟整个方法,要么只进行修改(在第二种情况下,默认情况是什么都不做)

    例如:(修正版)

    我希望,我得到了一个正确的,我的C++有点灰尘…… _计算似然必须由子类实现,并且计算似然绑定在一起


    当然,此解决方案会增加一点开销,但在某些情况下,开销可能还可以。

    正如您所指出的,编写大量基本传递函数非常繁琐,并且会增加隐含的维护开销。此外,拥有指针成员意味着拥有指针的额外(尽管很简单)生命周期管理问题。解决这些问题的最简单方法可能是将AdaptedGaussian作为模板,模板化在要调整的Gaussian的特定实例上

    template<class BaseGaussian> class AdaptedGaussian : public BaseGaussian
    {
        virtual double calculate_likelihood(Vector &data) 
        { 
            // do something with data
            return BaseGaussian::calculate_likelihood(Vector &data); 
        }
    };
    

    嗯,当我只有一个指向现有高斯分布的指针时,我如何构造一个AdaptedGaussian?也许我误解了,在这个解决方案中,AdaptedGaussian是一个被适应的特定类型的高斯分布的实例。如果你想要一个适应的对角高斯分布,你可以创建一个适应的高斯分布而不是普通的对角高斯分布。由于AdaptedGaussian是一个T,您可以使用AdaptedGaussian的指针和引用作为T的指针和引用。当您说:“AdaptedGaussian必须能够“包装”或“成为”每个可能的Gaussian类的实例”时,我假设(a)包装现有实例不是一个要求,因此(b)指针的使用是一个实现细节,因为您的目标是“包装”解决方案,而不是“实例”解决方案。我是否遗漏了您的问题中的一些关键要求?很抱歉,我的问题不完全清楚。要求是该类以某种方式表示一个已经存在的类。我不知道或者有一种方法可以实现这一点而不调用包装?在这种情况下,我认为通过我添加的构造函数,这个解决方案可以工作。不过,这取决于你的具体情况。正确AdaptedGaussian的构造取决于具有正确静态类型的指针或引用。如果你有一个对角的高斯指针,那么你可以用它构造一个AdaptedGaussian,如果你所拥有的只是一个高斯指针,恰好指向一个对角的高斯实例,那么你已经扔掉了一些静态类型信息,需要一个依赖于运行时多态性的解决方案,比如你所发布的。这个想法并不完全有效。每个子类都有自己的calculate_似然实现,因此不会有相应的数据。除此之外,我希望这个功能完全在当前类之外。这是因为此功能可能以不同的方式/方法实现,并且仅在少数应用程序运行中使用。感谢您的反馈。当然,我也可以尽可能多地暗示,因为我理解这个问题。这就是我写“也许”的原因。从您的代码片段来看,整个上下文不是很清楚。当每个子类都有自己的calculate_likelion实现时,怎么可能比您的示例更有效呢?因为它对它也有一些限制??我不明白为什么我的示例不起作用。由于calculate_似然在高斯中是虚拟的(没有实现,请参见=0),因此将执行真实对象的calculate_似然函数
    template<class BaseGaussian> class AdaptedGaussian : public BaseGaussian
    {
        virtual double calculate_likelihood(Vector &data) 
        { 
            // do something with data
            return BaseGaussian::calculate_likelihood(Vector &data); 
        }
    };
    
    template<class BaseGaussian> class AdaptedGaussian : public BaseGaussian
    {
    public:
        AdaptedGaussian(const BaseGaussian& other) : BaseGaussian(other)
        {
        }
        // ...
    };