多个"level"派生抽象类

Multiple "level" derived abstract classes with

本文关键字:抽象类 派生 level 多个      更新时间:2023-10-16

我在C++有问题

  • 一个具有公共成员和纯虚函数的抽象基类。这在下面的代码中A
  • 具有不同成员和函数的多个派生类。这在下面的代码中BC
  • 实现虚函数且没有新成员的多个派生类。这在下面的代码中do_stuff_1do_stuff_2

到目前为止,我的解决方案是混合模板和抽象类。目标是持有指向抽象类的指针BC并调用do_stuff 。我的问题是

  1. 我的解决方案好吗?
  2. 如果没有,有更好的解决方案吗?
  3. 如果是这样,我应该注意一些陷阱吗?

这是我到目前为止的解决方案

#include <iostream>
#include <memory>
/* base virtual class */
class A {
public:
  int a;
  A(int a) : a(a) {}
  virtual void do_stuff() = 0;
};
/* concrete implementations of do_stuf */
template<class T>
class do_stuff_1 : public T {
public:
  using T::T;
  void do_stuff(){
    std::cout << "do_stuff_1 " << this->a << std::endl;
  }
};
template<class T>
class do_stuff_2 : public T {
public:
  using T::T;
  void do_stuff(){
    std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
  }
};
/* derived classes from A */
class B : public A {
public:
  int b;         // one member here but many more in my application
  B(int a, int b): A(a), b(b) {}
};
class C : public A {
public:
  std::string c; // one member here but many more in my application
  C(int a, std::string c): A(a), c(c) {}
};
int main() {
  std::unique_ptr<B> x;
  x.reset(new do_stuff_1<B>(1, 1));
  x->do_stuff();
  std::cout << x->b << std::endl;
  x.reset(new do_stuff_2<B>(1, 2));
  x->do_stuff();
  std::cout << x->b << std::endl;
  std::unique_ptr<C> z;
  z.reset(new do_stuff_1<C>(1, "Yo"));
  z->do_stuff();
  std::cout << z->c << std::endl;
  z.reset(new do_stuff_2<C>(1, "Hello"));
  z->do_stuff();
  std::cout << z->c << std::endl;
  return 0;
}

结果是

do_stuff_1 1                                                                                                                                     
1                                                                                                                                                
do_stuff_2 2                                                                                                                                     
2                                                                                                                                                
do_stuff_1 1                                                                                                                                     
Yo                                                                                                                                               
do_stuff_2 2                                                                                                                                     
Hello 

您的解决方案似乎很好。这是一种编译时方法,您可以创建 4 个不同的对象。

主要缺点是:

  • 除非实例化模板,否则您将不知道do_stuff()代码是否正确。
  • 您可以使用不属于基类 A 的类实例化do_stuff_1do_stuff_2。 您至少应该在模板中使用override以确保它覆盖虚拟函数。

这里有一个小小的改进来解决这些问题:

template<class T>
class do_stuff_2 : public T {
public:
  using T::T;
  void do_stuff() override {
    static_assert (std::is_base_of<A, T>::value, "T should be derived from A");
    std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
  }
};

顺便说一句,使用make_unique会很好。

对我来说

看起来像某种政策,这可能看起来像:

#include <iostream>
#include <memory>
#include <type_traits>
struct AwayToDoTheStuff {
    virtual void operator()(int a) = 0;
    virtual ~AwayToDoTheStuff() {}
};
/* concrete implementations of do_stuf */
class HowToDoStuff1 : public AwayToDoTheStuff {
    public:
        void operator()(int a) override {
            std::cout << "do_stuff_1 " << a << std::endl;
        }
};
class HowToDoStuff2 : public AwayToDoTheStuff {
    public:
        void operator()(int a) override {
            std::cout << "do_stuff_2 " << a + 1 << std::endl;
        }
};
/* base virtual class */
template <class HowToDoStuff>
class A {
    public:
        int a;
        A(int a) : a(a) {}
        void do_stuff() {
            static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
            HowToDoStuff()(a);
        }
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public A<HowToDoStuff> {
    public:
        int b;         // one member here but many more in my application
        B(int a, int b): A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public A<HowToDoStuff> {
    public:
        std::string c; // one member here but many more in my application
        C(int a, std::string c): A<HowToDoStuff>(a), c(c) {}
};
int main() {
    B<HowToDoStuff1>(1, 1).do_stuff();
    B<HowToDoStuff2>(1, 2).do_stuff();
    C<HowToDoStuff1>(1, "Yo").do_stuff();
    C<HowToDoStuff2>(1, "Hello").do_stuff();
    return 0;
}

但我必须说,这很难判断解决方案是否与如此通用的示例匹配。我希望它能在某些方面帮助你...

编辑

您似乎需要一个公共基类,以便可以将对象 B 和 C 传递给此类公共函数void f(A &a);

那么我的例子可以这样改编:

/* base virtual class */
class A {
    public:
        void do_stuff() = 0;
};
template <class HowToDoStuff>
class Policy_A : public A {
    public:
        int a;
        A(int a) : a(a) {}
        void do_stuff() override {
            static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
            HowToDoStuff()(a);
        }
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public Policy_A<HowToDoStuff> {
    public:
        int b;         // one member here but many more in my application
        B(int a, int b): Policy_A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public Policy_A<HowToDoStuff> {
    public:
        std::string c; // one member here but many more in my application
        C(int a, std::string c): Policy_A<HowToDoStuff>(a), c(c) {}
};

以便可以在不透明的 A 对象上调用do_stuff。

您也可以在创建时传递 HowToDoStuff 对象:

/* base virtual class */
class A {
    std::unique_ptr<AwayToDoTheStuff> _stuffer;
    public:
        int a;
        A(std::unique_ptr<AwayToDoTheStuff> stuffer, int a) : _stuffer(std::move(stuffer)), a(a) {}
        void do_stuff() {
            (*_stuffer)(a);
        }
};
/* derived classes from A */
class B : public A {
    public:
        int b;         // one member here but many more in my application
        B(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, int b): A(std::move(stuffer), a), b(b) {}
};
class C : public A {
    public:
        std::string c; // one member here but many more in my application
        C(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, std::string c): A(std::move(stuffer), a), c(c) {}
};
int main() {
    auto stuffer1forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
    auto stuffer2forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
    B(stuffer1forB, 1, 1).do_stuff();
    B(stuffer2forB, 1, 2).do_stuff();
    auto stuffer1forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
    auto stuffer2forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
    C(stuffer1forC, 1, "Yo").do_stuff();
    C(stuffer2forC, 1, "Hello").do_stuff();
    return 0;
}