C++ 多态性:如何创建派生 class 对象

C++ polymorphism: how to create derived class objects

我有一个名为 BaseStrategy 的抽象基 class。它包含一个纯虚函数calculateEfficiency()。有两个 classes ConvolutionStrategyMaxPoolStrategy 派生自这个基础 class 并实现它们自己的特定版本 calculateEfficiency().

这是一些代码:

class BaseStrategy {
public:
    explicit BaseStrategy();
    virtual ~BaseStrategy() = default;

private:
    virtual double calculateEfficiency(mlir::Operation* op) = 0;
};

class ConvolutionStrategy : public BaseStrategy {
private:
    double calculateEfficiency(mlir::Operation* op)
    {
        //some formula for convolution 
        return 1;
    }
};

class MaxPoolStrategy : public BaseStrategy {
private:
    double calculateEfficiency(mlir::Operation* op)
    {
        //some formula for MaxPool
        return 1;
    }
};

现在我有另一个 class 叫做 StrategyAssigner。它有方法 calculateAllLayerEfficiencies() ,其目的是遍历网络中的所有层。根据层的类型,有一个 switch 语句,应该根据层类型调用正确的 calculateEfficiency()

class StrategyAssigner final {
public:
    explicit StrategyAssigner(){};

public:
    void calculateAllLayerEfficiencies() {
        // Logic to iterate over all layers in
        // a network
        switch (layerType) {
        case Convolution:
            // Call calculateEfficiency() for Convolution
            break;
        case MaxPool:
            // Call calculateEfficiency() for MaxPool
            break;
        }
    };
}

int main ()
{
    StrategyAssigner assigner;
    assigner.calculateAllLayerEfficiencies();
}

我的问题是,我是否应该将对象 Convolution 和 MaxPool 的引用存储在 class StrategyAssigner 中,以便我可以调用相应的 calculateEfficiency().

或者您能否建议一种更好的调用方式 calculateEfficiency()。我真的不知道如何创建对象(听起来很愚蠢)。

我不能让 calculateEfficiency() 静态,因为我需要它们是虚拟的,这样每个派生的 class 都可以实现自己的公式。

如果您包含完整的代码,我可以给出更详细的答案,但您需要存储使用派生 class 实例初始化的 BaseStrategy 指针。这是根据您的一些代码制作的示例:

std::vector<std::unique_ptr<BaseStrategy>> strategies;
strategies.emplace_back(new ConvolutionStrategy);
strategies.emplace_back(new MaxPoolStrategy);

for (int i = 0; i < strategies.size(); ++i) {
    std::unique_ptr<BaseStrategy>& pStrat = strategies[i];
    pStrat->calculateEfficiency(...);
}

请注意,这不会编译,因为我没有从您发布的代码中获得足够的细节来编译它,但这展示了如何以您需要的方式利用多态性。

另外,我使用了智能指针来进行内存管理;请自行决定使用这些。

你确实可以在这里使用运行时多态性:

  • 声明 ~BaseStrategy 虚拟(您已经在做 ;-)
  • 如果您永远不会实例化一个 BaseStrategy,请将其中一个方法声明为虚拟纯方法,例如calculateEfficiency(你也已经在做了!)。我会制作该方法 const,因为它看起来不会修改实例。它需要是 public,因为它需要从 StrategyAnalyser.
  • 访问
  • 在每个子 class 中将 calculateEfficiency 声明为 virtualoverride。如果您不想子 class 覆盖它,它也可以是 final
  • 我会在 StrategyAssigner 处保留 std::vector 个指向 BaseStrategy 的智能指针。如果您认为 class 不会共享这些指针,则可以使用 unique_ptrs。
  • 现在的关键点是创建子classes 的堆实例并将它们分配给基class.
  • 的指针
class StrategyAssigner final {
public:
    void addStrategy(std::unique_ptr<BaseStrategy> s) {
        strategies_.push_back(std::move(s));
    }
private:
    std::vector<std::unique_ptr<BaseStrategy>> strategies_{};
};

int main()
{
    StrategyAssigner assigner;
    assigner.addStrategy(std::make_unique<ConvolutionStrategy>());
}
  • 然后,当您使用这些指向 BaseStrategy 的指针中的任何一个调用 calculateEfficiency 时,运行时多态性将启动,它将是 subclass 的方法将实际调用。
class ConvolutionStrategy : public BaseStrategy {
private:
    virtual double calculateEfficiency() const override {
        std::cout << "ConvolutionStrategy::calculateEfficiency()\n";
        return 10;
    }
};

class MaxPoolStrategy : public BaseStrategy {
private:
    virtual double calculateEfficiency() const override {
        std::cout << "MaxPoolStrategy::calculateEfficiency()\n";
        return 20;
    }
};

class StrategyAssigner final {
public:
    void calculateAllLayerEfficiencies() {        
        auto sum = std::accumulate(std::cbegin(strategies_), std::cend(strategies_), 0,
            [](auto total, const auto& strategy_up) {
                return total + strategy_up->calculateEfficiency(); });
        std::cout << "Sum of all efficiencies: " << sum << "\n";
    };
};

int main()
{
    StrategyAssigner assigner;
    assigner.addStrategy(std::make_unique<ConvolutionStrategy>());
    assigner.addStrategy(std::make_unique<MaxPoolStrategy>());
    assigner.calculateAllLayerEfficiencies(); 
}

// Outputs:
//
//   ConvolutionStrategy::calculateEfficiency()
//   MaxPoolStrategy::calculateEfficiency()
//   Sum of all efficiencies: 30

[Demo]