Polymorphism with new data members

我的未来我决定 提交于 2019-12-22 09:37:40

问题


I would like to write a function that can initialize and return objects of different classes using polymorphism. I also would like these classes to have different data members which may be called through the virtual function. What I wrote below might work. Could you check if I have some undefined behavior in there? Thank you! One thing I am worried about is that when I call "delete polypoint" at the end it will not free the data member "scale" that is unique to "CRectangle". If my code doesn't work is there a way to make it work?

class CPolygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area ()
      { return (0); }
  };

class CRectangle: public CPolygon {
  public:
    int scale;
    int area ()
      { return (width * height * scale ); }
  };

CPolygon *polytestinner()
{
    CPolygon *polypoint = 0;

    int consoleinput = 2;
    if (consoleinput>1)
    {
        CRectangle *rectpoint = new CRectangle();
        rectpoint->scale = 4;
        polypoint = rectpoint;
    }
    polypoint->set_values(3,4);
    return polypoint;
}

void polytest()
{
    CPolygon *polypoint = polytestinner();
    gstd::print<int>(polypoint->area());    
    delete polypoint;
}

int main()
{
    polytest();
    return 0;
}

Thank you!


回答1:


I feel compelled to point out Andrei Alexandrescu's object factory architecture. It allows your architecture to grow without having to modify the factory every time you create a concrete type. It is based on a "callback register", and it is actually implemented as a generic component in some libraries. The code is below.

Live Code Example

#include<map>
#include<iostream>
#include<stdexcept>

// your typical base class
class Shape {
 public:
  virtual void Draw() const = 0;
  // virtual destructor allows concrete types to implement their own
  // destrucion mechanisms
  virtual ~Shape() {} 
};

// this factory architecture was suggested by Andrei Alexandrescu in
// his book "Modern C++ Design" --- read it to get the full
// explanation (and a more generic implementation); this is just an
// example
class ShapeFactory {
 public:
  // this typedef allows to "name" arbitrary functions which take no
  // arguments and return a pointer to a Shape instance
  typedef Shape* (*CreateShapeCallback)();

  Shape* CreateShape(int ShapeId) {
    // try to find the callback corresponding to the given shape id;
    // if no shape id found, throw exception
    CallbackMap::const_iterator it = m_callbacks.find(ShapeId);
    if(it == m_callbacks.end()) {
      throw std::runtime_error("unknown shape id");
    } else {
      // create the instance using the creator callback
      return (it->second)();
    }    
  }

  bool RegisterShape(int ShapeId, CreateShapeCallback Creator) {
    // returns true if shape was registered; false if it had already
    // been registered
    return m_callbacks.insert(CallbackMap::value_type(ShapeId, Creator)).second;
  }

  bool UnRegisterShape(int ShapeId) {
    // returns true if shape was unregistered, false if it was not
    // registered in the first place
    return m_callbacks.erase(ShapeId) == 1;
  }

 private:
  // the typedef simplifies the implementation
  typedef std::map<int, CreateShapeCallback> CallbackMap;
  // the callbacks are stored in a map int->callback (see typedef
  // above)
  CallbackMap m_callbacks;
};


// create some concrete shapes... you would do this in other CPP files
class Line : public Shape {
 public:
  void Draw() const {
    std::cout<<"Drawing a line"<<std::endl;
  }
};

// another concrete shape...
class Circle : public Shape {
 public:
  void Draw() const {
    std::cout<<"Drawing a circle"<<std::endl;
  }
};
// ... other concrete shapes...

enum ShapeIds {LINE=1, CIRCLE, COUNT};
Shape* CreateLine() { return new Line; }
Shape* CreateCircle() { return new Circle; }


int main() {
  // suppose this is the "singleton" instance for the ShapeFactory
  // (this is an example! Singletons are not implemented like this!)  
  ShapeFactory *factory = new ShapeFactory;
  factory->RegisterShape(ShapeIds::LINE, CreateLine);
  factory->RegisterShape(ShapeIds::CIRCLE, CreateCircle);

  Shape* s1 = factory->CreateShape(ShapeIds::CIRCLE);
  Shape* s2 = factory->CreateShape(ShapeIds::LINE);
  s1->Draw();
  s2->Draw();
  // will throw an error
  try {
    Shape *s3 = factory->CreateShape(-1);
    s3->Draw();    
  } catch(const std::exception& e) {
    std::cout<<"caught exception: "<<e.what()<<std::endl;    
  }
  return 0;
}



回答2:


CPolygon needs a virtual destructor:

virtual ~CPolygon() {}



回答3:


You have undefined behavior in your code:

  CPolygon *polypoint;
  delete polypoint;

deleting a base class pointer when there is no virtual destructor will result in undefined behavior.

Your CPolygon class and CRectangle classes have no destructors, though the compiler will generate default destructor for you in this case, but they are not virtual by default. Therefore, you need to at least define a virtual destructor for your base class, i.e., CPolygon.



来源:https://stackoverflow.com/questions/15977617/polymorphism-with-new-data-members

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!