home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / lang / cplus / 18943 < prev    next >
Encoding:
Text File  |  1993-01-11  |  3.0 KB  |  95 lines

  1. Newsgroups: comp.lang.c++
  2. Path: sparky!uunet!brunix!brunix!sdm
  3. From: sdm@cs.brown.edu (Scott Meyers)
  4. Subject: Re: Preventing inheritance
  5. Message-ID: <1993Jan11.154735.17187@cs.brown.edu>
  6. Sender: news@cs.brown.edu
  7. Organization: Brown University Department of Computer Science
  8. References: <1iqtnpINN283@news.cerf.net>
  9. Date: Mon, 11 Jan 1993 15:47:35 GMT
  10. Lines: 83
  11.  
  12. In article <1iqtnpINN283@news.cerf.net> hlf@nic.cerf.net (Howard Ferguson) writes:
  13. | If I create a class which I am supplying to other users, how do I
  14. | make sure that they do not inherit from it ever. I could overload new
  15. | and check the size of the object that is being allocated, but there
  16. | are two catchs. The first minor one is that this is a run-time check,
  17. | and it would be far preferable to catch this sort of thing at compile
  18. | time. More seriously, they could over-ride the new operator and by-pass
  19. | the check.
  20.  
  21. More seriously still, not all objects are allocated on the heap, so new
  22. isn't always called. 
  23.  
  24. The solution to your problem sort of depends on whether you want to prevent
  25. actual derivation or "moral" derivation.  If you only want to prevent
  26. actual derivation, make everything in the class private and then create a
  27. second class which is a friend to the first one:
  28.  
  29.   class StandAlone {      // nobody should derive from this class
  30.     private:
  31.        int x, y, z;
  32.     
  33.         StandAlone();
  34.         ~StandAlone();
  35.         void foo();
  36.         int bar() const;
  37.  
  38.     friend class UseMe;   // this is the class clients actually use
  39.   };
  40.  
  41. UseMe contains an instance of StandAlone, and calls to functions in UseMe
  42. are just forwarded to this object:
  43.  
  44.   class UseMe {
  45.     private:
  46.       StandAlone s;
  47.  
  48.     public:
  49.         UseMe() {}
  50.         ~UseMe() {}
  51.         void foo() { s.foo(); }
  52.         int bar() const { return s.bar(); }
  53.   };
  54.  
  55. You get extra style points for nesting StandAlone inside UseMe.  If you do,
  56. not that StandAlone's members still need to be private, otherwise friends
  57. of UseMe would have access to StandAlone.
  58.  
  59. There are two problems with this approach.  First, it's not utterly
  60. iron-clad, because UseMe can still derive from StandAlone, like this:
  61.  
  62.   class UseMe {
  63.     class Nested: public StandAlone { ... };
  64.   };
  65.  
  66. Second, it doesn't prevent "moral" derivation:  clients can still use UseMe
  67. as a base class, and you may not want that.
  68.  
  69. A different -- substantially less direct -- approach to the problem is to
  70. just declare Standalone in the usual manner, but without any virtual
  71. functions:
  72.  
  73.   class StandAlone {      // nobody should derive from this class
  74.     private:
  75.        int x, y, z;
  76.     
  77.     public:
  78.         StandAlone();
  79.         ~StandAlone();
  80.         void foo();
  81.         int bar() const;
  82.   };
  83.  
  84. Because none of the functions is declare virtual -- notably the destructor
  85. -- you might hope that clients catch on that this class is not designed for
  86. use as a base class.  Unfortunately, that's the only thing you've got going
  87. for you in this case: hope.
  88.  
  89. Scott
  90.  
  91.  
  92. -------------------------------------------------------------------------------
  93. What do you say to a convicted felon in Providence?  "Hello, Mr. Mayor."
  94.