如何在派生类中将策略模式与其他方法一起使用

时间:2019-03-07 09:22:00

标签: c++ algorithm design-patterns

我正在编写一个我在其中使用策略的项目,但是,我的派生类还具有基类不应该具有的其他附加功能。

class Base {
        public:
            virtual void execute() = 0;
            virtual void print() const noexcept = 0;
            virtual ~Base() {}
        };


class DerivedA : public virtual Base {
        public:
            void execute() override;
            void print() const noexcept override;
            void doSomething();

        private:
            int x;
            double y;
};

class DerivedB final : public Base {
        public:
            void execute() override;
            void print() const noexcept override;
            std::string getZ() const noexcept;

        private:
            std::string z;
        };


在main()中,我试图使用dynamic_cast来使用以下附加功能:

int main() {

    DerivedA da;
    Base* base = &da;
    DerivedA* derivedA = dynamic_cast<DerivedA*>(base);
    derivedA.doSomething();

    return 0;
}


但是,当我尝试运行代码时,出现以下错误:

“ DerivedA *”的间接级别与“ DerivedA”

不同


我的问题是,我是否应该为此使用策略,还是应该使用其他设计模式?如果我应该使用策略,该如何解决这个错误?


更新

我正在考虑切换到装饰器,因为DerivedA可以是DerivedB的基类,但是,我担心转换,因为每个类都有不同的类成员。


更新

似乎我写错了演员表。但是,我在这里张贴时写的正确!现在可以使用,但是,我同意,有一种更好的方法可以实现这一点。

3 个答案:

答案 0 :(得分:2)

如果这正是您要编译的代码,则解决方案很容易。代替

derivedA.doSomething();

您应该写

derivedA->doSomething();

由于派生的是指针,而不是引用或实例。

但是,对于考虑dynamic_cast,我还有其他一些严重的担忧。我的意见是,如果您使用dynamic_cast,则可能是您的设计有问题。您有一个隐藏实现的接口,但有一些代码依赖于实现而不是在接口中。

要考虑的一些替代方法:

  • 尝试将实现特定的方法转换为对接口有意义的方法。也许您可以在所有实现中找到一些通用概念。
  • 将特定于实现的方法提取到“功能”接口中,并在该接口中提供功能以获得“功能”接口。例如。如果您的基类是IAnimal,并且您的某些动物可以游泳,请创建一个界面ISwimmable,然后向IAnimal添加一个方法,该方法返回指向ISwimmable的指针({{ 1}})。可以游泳的动物实现可以从IAnimal::getSwimmable继承并实现ISwimmable并返回指向getSwimmable接口的指针(因此,实际上返回其自身,这只是隐式本身)。不会游泳的动物可以返回ISwimmable(如果您想保留接口a,它可能是nullptr中的默认实现,或者是从IAnimal继承的某些AnimalBase类纯接口)。

Microsoft的COM系统还使用了第二种方法,其中每个COM接口都实现了IAnimal接口,并且您可以调用IUnknown来获取特定的不同接口以实现某些“功能”。

答案 1 :(得分:1)

在iw工作文件下面的代码为我提供了g ++和编译功能: g ++ main.cc -o main -std = c ++ 14

#include <string>

class Base {
        public:
            virtual void execute() = 0;
            virtual void print() const noexcept = 0;
            virtual ~Base() {}
        };


class DerivedA : public virtual Base {
        public:
            void execute() override {}
            void print() const noexcept override {}
            void doSomething(){}

        private:
            int x;
            double y;
};

class DerivedB final : public Base {
        public:
            void execute() override {}
            void print() const noexcept override {}
            std::string getZ() const noexcept {}

        private:
            std::string z;
        };
int main() {

    DerivedA da;
    Base* base = &da;
    DerivedA* derivedA = dynamic_cast<DerivedA*>(base);
    derivedA->doSomething();

    return 0;
}

答案 2 :(得分:1)

您所描述的是软件中的一个常见问题,并且在各种设计模式中都出现了很多问题。您想多态使用DerivedADerivedB,因此它们必须共享一个公共接口。没关系。但是,DerivedA有一个您也想使用的有用方法doSomething。您可以选择以下两种方式:

  1. 不要使用doSomething方法,这会使您的代码保持整洁;
  2. 进行运行时类型检查并进行强制转换,以便您可以访问doSomething,但是您的代码不可避免地看起来有些hacky;
  3. doSomething中执行Base不执行任何操作,那么代码看起来不错,但是当您在doSomething引用上调用Base时,如果接收到对象实际上是类DerivedB中的对象。

装饰器在这里并没有真正的帮助。装饰器非常适合扩充现有方法。如我所知,您不能使用它(以静态类型的语言)添加新方法:-)