2

Inherit without virtual destructor

 2 years ago
source link: https://www.codesd.com/item/inherit-without-virtual-destructor.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Inherit without virtual destructor

advertisements

I have two classes that are used in a project. One class, Callback, is in charge of holding information from a callback. Another class, UserInfo, is the information that is exposed to the user. Basically, UserInfo was supposed to be a very thin wrapper that reads Callback data and gives it to the user, while also providing some extra stuff.

struct Callback {
  int i;
  float f;
};

struct UserInfo {
  int i;
  float f;

  std::string thekicker;
  void print();
  UserInfo& operator=(const Callback&);
};

The problem is that adding members to Callback requires identical changes in UserInfo, as well as updating operator= and similarly dependent member functions. In order to keep them in sync automatically, I want to do this instead:

struct Callback {
  int i;
  float f;
};

struct UserInfo : Callback{
  std::string thekicker;
  void print();
  UserInfo& operator=(const Callback&);
};

Now UserInfo is guaranteed to have all of the same data members as Callback. The kicker is, in fact, the data member thekicker. There are no virtual destructors declared in Callback, and I believe the other coders want it to stay that way (they feel strongly against the performance penalty for virtual destructors). However, thekicker will be leaked if a UserInfo type is destroyed through a Callback*. It should be noted that it is not intended for UserInfo to ever be used through a Callback* interface, hence why these classes were separate in the first place. On the other hand, having to alter three or more pieces of code in identical ways just to modify one structure feels inelegant and error-prone.

Question: Is there any way to allow UserInfo to inherit Callback publicly (users have to be able to access all of the same information) but disallow assigning a Callback reference to a UserInfo specifically because of the lack of virtual destructor? I suspect this is not possible since it is a fundamental purpose for inheritance in the first place. My second question, is there a way to keep these two classes in sync with each other via some other method? I wanted to make Callback a member of UserInfo instead of a parent class, but I want data members to be directly read with user.i instead of user.call.i.

I think I'm asking for the impossible, but I am constantly surprised at the witchcraft of stackoverflow answers, so I thought I'd ask just to see if there actually was a remedy for this.


You could always enforce the 'can't delete via base class pointer' constraint that you mentioned (to some extent) by making the destructor protected in the base class:

// Not deletable unless a derived class or friend is calling the dtor.
struct Callback {
  int i;
  float f;
protected:
  ~Callback() {}
};

// can delete objects of this type:
struct SimpleCallback : public Callback {};

struct UserInfo : public Callback {
  std::string thekicker;
  // ...
};

As others have mentioned, you can delete the assignment operator. For pre-c++11, just make an unimplemented prototype of that function private:

private:
  UserInfo& operator=(const Callback&);

Tags c++11

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK