首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >继承类中子类操作的C++设计模式

继承类中子类操作的C++设计模式
EN

Stack Overflow用户
提问于 2012-04-18 17:11:26
回答 3查看 201关注 0票数 0

我有一个抽象基类,它对所有派生类强制执行某些操作。除此之外,我还想强制执行特定于派生类中声明的子类的某些其他操作。

以下是一个最小的例子:

代码语言:javascript
复制
class Base {
    public:
        virtual void init() = 0;
        virtual void reset() = 0;
};

class Derived1 : public Base {
    class Data {
        int *x1;
    public:
        Data() {
            x1 = NULL;
        }

        void alloc(int num) {
            x1 = new int[num];
        }

        ~Data() {
            delete[] x1;
            x1 = NULL;
        }
    } data;

public:
    void init() { ... }
    void reset() { ... }

    void resetData() { 
        data.~Data(); 
    }
};

class Derived2 : public Base {
    class Data {
        float *x2;
    public:
        Data() {
            x2 = NULL;
        }

        void alloc(int num) {
            x2 = new float[num];
        }

        ~Data() {
            delete[] x2;
            x2 = NULL;
        }
    } data;

public:
    void init() { ... }
    void reset() { ... }

    void resetData() { 
        data.~Data(); 
    }
};

在上面的示例中,Base对所有派生类强制执行init()和重置()方法。

除此之外,我还想强制执行所有派生类都具有

  1. 是命名数据的成员变量,
  2. 是调用该变量
  3. 上析构函数的方法resetData(),该方法称为Data &getData(),用于引用变量

G 210

实现这一目标的最佳途径是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-04-19 07:43:23

谢谢你的答复。这就是我想出来的。我知道我违背了最初的要求,即数据必须是派生类的子类,但是下面的设计模式确保所有派生类都有一个data成员变量,每个成员变量的类型不同,但同样,每个派生类都有一些基本方法强制执行。我认为这就是@emsr在他的评论中所建议的。

现在,resetData()是在一个单独的方法中完成的。感谢@LuchianGrigore指出了显式调用析构函数可能存在的问题。现在,这个方法显式地代替了。虚拟析构函数也将调用相同的函数。我知道我不应该从析构函数调用虚拟函数,但是通过显式设置函数的范围,我希望在这里避免任何模糊。(或者这也是个问题?)

代码语言:javascript
复制
struct Data {
    virtual void resetData() = 0;
    virtual ~Data() {}
};

template<typename _DT>
class Base {
protected:
    _DT data;

public:
    _DT &getData() {
        return data;
    }

    void resetData() {
        data.resetData();
    }

    virtual void init() = 0;
    virtual void reset() = 0;
};

struct Data1 : public Data {
    int *x;

    Data1() {
        x = NULL;
    }

    void alloc(int num) {
        x = new int[num];
    }

    virtual void resetData() {
        delete[] x;
        x = NULL;
    }

    virtual ~Data1() {
        Data1::resetData();
    }

};

class Derived : public Base<Data1> {
public:
    virtual void init() {
        // Carry out other init operations
        Data1 &x = getData();
        x.alloc(10);
    }

    virtual void reset() {
        // Carry out other reset operations
        data.resetData();
    }
};
票数 0
EN

Stack Overflow用户

发布于 2012-04-18 17:13:34

  • 是命名数据的成员变量,
  • 是一个名为resetData()的方法,它调用这个变量
  • 上的析构函数,一个名为data &getData()的方法,用于获取对变量

的引用。

在我看来,如果这些在所有派生类中都是常见的,那么您需要在基类中使用它们。

代码语言:javascript
复制
class Base {
    public:
        Data data;
        void resetData();  //if data is not a pointer, are you sure you want 
                           //to call its destructor?
                           //this will lead to undefined behavior when
                           //Base is destroyed, as data will automatically 
                           //be freed
        Data& getData();
        virtual void init() = 0;
        virtual void reset() = 0;
};

你的课仍然是抽象的,以防万一这是个问题。

没有这种方法的

  • 没有办法强制执行派生类,声明一个成员
  • ,您可以查看模板方法模式,但是,我仍然看不到纯虚拟getData
  • 点,但是,我仍然看不到H 222f 223

从设计的角度来看,所有这些都应该在基类中。

票数 2
EN

Stack Overflow用户

发布于 2012-04-18 19:28:17

我将在数据类型上模板基类,并将数据定义移出派生类。缺点是,您不再有一个单一类型的基础。

代码语言:javascript
复制
template <class Data>
class Base {
public:
  virtual ~Base() {}
  virtual void init() = 0;
  virtual void reset() = 0;
  virtual Data& getData() {
    return data;
  }
  virtual void resetData() {
    data.reset();
  }

protected:
  Data data;
};

class Data1 {
  int *x1;
public:
  Data1() {
    x1 = 0;
  }

  void alloc(int num) {
    x1 = new int[num];
  }

  void reset() {
    delete[] x1;
    x1 = 0;
  }

  ~Data1() {
    delete[] x1;
    x1 = 0;
  }
};



class Derived1 : public Base<Data1> {
public:

public:
  void init() { }
  void reset() { }
};


class Data2 {
  float *x2;
public:
  Data2() {
    x2 = 0;
  }

  void reset() {
    delete[] x2;
    x2 = 0;
  }

  void alloc(int num) {
    x2 = new float[num];
  }

  ~Data2() {
    delete[] x2;
    x2 = 0;
  }
};


class Derived2 : public Base<Data2> {
public:
public:
  void init() { }
  void reset() { }
  Data2& getData() {
    return data;
  }
  void resetData() {
    data.reset();
  }
};

另一种方法是从单个基类继承数据类。在这种情况下,您将无法强制成员变量的名称是数据。

代码语言:javascript
复制
class IData {
public:
  virtual ~IData() {}
  virtual void reset() = 0;
};

class Base {
public:
  virtual ~Base() {}
  virtual void init() = 0;
  virtual void reset() = 0;
  virtual IData& getData() = 0;
  virtual void resetData() = 0;
};

class Derived1 : public Base {
  class Data : public IData {
    int *x1;
  public:
    Data() {
      x1 = 0;
    }

    void alloc(int num) {
      x1 = new int[num];
    }

    void reset() {
      delete[] x1;
      x1 = 0;
    }

    ~Data() {
      delete[] x1;
      x1 = 0;
    }
  } data;

public:
  void init() { }
  void reset() { }

  IData& getData() {
    return data;
  }
  void resetData() {
    data.reset();
  }
};

class Derived2 : public Base {
  class Data : public IData {
    float *x2;
  public:
    Data() {
      x2 = 0;
    }

    void reset() {
      delete[] x2;
      x2 = 0;
    }

    void alloc(int num) {
      x2 = new float[num];
    }

    ~Data() {
      delete[] x2;
      x2 = 0;
    }
  } data;

public:
  void init() { }
  void reset() { }
  IData& getData() {
    return data;
  }
  void resetData() {
    data.reset();
  }
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10214443

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档