prohibiting creation and hidden classes

This is a discussion on prohibiting creation and hidden classes within the C++ Programming forums, part of the General Programming Boards category; this might sound useless/needless, but bear with me.. I'm just toying with some OO i've been playing with some patterns ...

  1. #1
    Registered User
    Join Date
    Aug 2011
    Posts
    6

    prohibiting creation and hidden classes

    this might sound useless/needless, but bear with me.. I'm just toying with some OO

    i've been playing with some patterns to prohibit creation without hiding the the constructor + friend keyword (since i don't want an entire class exposed).
    so i came up with this thing:
    - big class that is allowed to instantiate the once i prohibit creation of
    it has two classes :
    - a private "real" class
    - a public proxy class for interacting with the "real"

    here's how it goes:
    Code:
    class SoupNazi
    {
    	private:	class HiddenSoup;
    	public:		class SoupProxy;
    
    public:
    	SoupNazi()	{ _real_soup = 0;}
    	~SoupNazi()	{}
    
    	void		makeSoup ();
    	void		spillSoup();
    	SoupProxy	gimmeProxy();	
    
    private:
    	HiddenSoup* _real_soup;
    
    };
    Code:
    	class SoupNazi::HiddenSoup
    	{
    	public:
    		HiddenSoup()	{ _val=0; }
    		~HiddenSoup()	{}
    
    		void	setVal	( int n )			{_val = n;}
    		int		getVal	( )			const	{ return _val; }
    
    	private:
    		int _val;
    	};
    Code:
    	class SoupNazi::SoupProxy
    	{
    	public:
    		SoupProxy	( SoupNazi::HiddenSoup* ref ) : _real(ref)	{ }
    		~SoupProxy	()	{ }
    
    		const SoupNazi::HiddenSoup* const operator->()	const	{return _real;}
    		SoupNazi::HiddenSoup*		const operator->()			{return _real;}
    
    	private:
    		SoupNazi::HiddenSoup* const _real;	
    	};
    use:
    Code:
    ...
    	SoupNazi nazi;
    	nazi.makeSoup();
    
    	SoupProxy proxy = nazi.gimmeProxy();
    	proxy->setVal(12);
    	std::cout<<proxy->getVal();
    
    	nazi.spillSoup();
    ...
    so, the only mechanism i am missing is a way to know if the proxy actually has a real soup pointed at, but can keep running without trying to access member of a null pointer..
    i hope i actually made this clear..
    idea?
    Last edited by nullspace; 08-05-2011 at 04:03 PM.

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,658
    Throw an exception if the construction of any of the objects fails. That way, it is not possible for a SoupProxy to even exist that contains an invalid object.

    If you want a class for which only one instance is allowed, loop up the singleton pattern. The shenanigans you are describing don't even come close to addressing that.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Sunshine, and read this, this, and this before posting again.

  3. #3
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,415
    You almost, but not quite, have yourself a "pimpl".

    By the way, the only compiler suite I know of that changes compilation based on access keywords (public, protected, and private) is long dead. In other words, what you are attempting to protect can be circumvent with two well placed '/' characters. My point isn't that you shouldn't use the access keywords, but that you should use them appropriately. There are known and mostly respected patterns to do what you want with associated use cases; use one of those instead as they will do what you want and imply a reason for doing it.

    As grumpy said, what you have doesn't prohibit creation of anything; it only disguised the fact that it doesn't prohibit creation.

    Soma

  4. #4
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,308
    Um that code is thoroughly broken.
    You can't have a constructor for class X inside class Y.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  5. #5
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,598
    The only two ways I know of to limit construction of an object is to hide the constructor, copy constructor, and assignment operator or use nested classes. Since C++ does not allow you to specify which classes or which type of objects may construct an object of a certain type the only way to allow an object to access the private portions of a class is to use friend. Friend can be used to restrict the usage of an object but it is usually used for operators that need access to the object. There are several problems with friend though that you must think about before using it. If you use it in the manner I suggested it only exposes the object to friends of the object so the exposure part is not a problem. However friend does not work for interfaces or facade type design patterns b/c friend is not inheritable. It does not work well with interfaces or class hierarchies b/c if object A is a friend of object B and C derives from A, C is not a friend of B. If you are using friend in this manner you must ask yourself why are you so keen on limiting the functionality of the creation of an object to one specific class? If it is for memory management concerns that can usually be resolved by using smart pointers. There are usually better approaches available that will be much more object oriented and will not have to break encapsulation even if for one specific object. There aren't a lot of benefits to limiting creation of objects to one specific object if you can guarantee that all objects will be managed correctly (IE: creation and destruction) by your code.

    Nested classes will give you the same benefits as friend (within the context of trying to limit creation to specific objects) but in a much cleaner fashion. If object B can only be created by object A then that would mean to me that object B is owned by object A and therefore B could be a nested class in A. Nested classes (and structures) to me imply ownership of said class (or structure).
    Last edited by VirtualAce; 08-05-2011 at 09:02 PM.

  6. #6
    Registered User
    Join Date
    Aug 2011
    Posts
    6
    Quote Originally Posted by grumpy View Post
    Throw an exception if the construction of any of the objects fails.
    i prefer to avoid throwing exception in cases that can be handled without them; what i am for is a way to query an object/list of objects and handle cases where nothing came back (yes i know this isn't implemented here).
    thinking about it now, i can just return a list of these and it can simply be empty..



    Quote Originally Posted by phantomotap View Post
    You almost, but not quite, have yourself a "pimpl"...

    ...There are known and mostly respected patterns to do what you want with associated use cases; use one of those instead as they will do what you want and imply a reason for doing it.
    apart from the pimpl, can you point me to some of these?

    Quote Originally Posted by iMalc View Post
    Um that code is thoroughly broken.
    You can't have a constructor for class X inside class Y.
    say what?

    @VirtualAce:
    so.. i guess im in the right direction..?

  7. #7
    Registered User
    Join Date
    Jun 2005
    Posts
    6,658
    Quote Originally Posted by nullspace View Post
    i prefer to avoid throwing exception in cases that can be handled without them; what i am for is a way to query an object/list of objects and handle cases where nothing came back (yes i know this isn't implemented here).
    That means you are asking to have your cake and eat it too.

    It is not possible to handle a case where "nothing came back" unless you can detect it. Detecting anything means doing some form of test (of validity, of containing "something", etc). However, you explicitly said you want things to work right in cases where "nothing came back" without doing any test.

    So your requirement is self-contradictory.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Sunshine, and read this, this, and this before posting again.

  8. #8
    Registered User
    Join Date
    Aug 2011
    Posts
    6
    err.. you seem to have some logic backing you there..

    anyhow, here's another one :
    i'm using Qt, and i didn't notice i need a qobject visible to use connect (if you don't know Qt.. well doesn't really matter )
    so i can either implement a get, or overload operator*.
    problem is that this exposes the ptr to delete.
    thought about using a reference (which would also help avoid a null or dead ptr), but that would pose a problem for derived classes of the hidden soup.
    also thought about overloading operator delete as a private, but it seems quite inappropriate to overload this scary operator as a semi-hack for "don't touch that" ( which is pretty much the logic i tried to avoid with by not using hidden ctors+friend class as a means to restrict creation..)

    thoughts?

  9. #9
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,308
    Quote Originally Posted by nullspace View Post
    say what?
    Oh wait, it looked like those classes inherrited from SoupNazi, but upon a second look, they are nested classes.
    I'll revise my statement. It is now simply "Yuck!"
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  10. #10
    Registered User
    Join Date
    Jun 2005
    Posts
    6,658
    Quote Originally Posted by nullspace View Post
    err.. you seem to have some logic backing you there..
    Logic is inconvenient when it contradicts what you want to do.
    Quote Originally Posted by nullspace View Post
    anyhow, here's another one :
    i'm using Qt, and i didn't notice i need a qobject visible to use connect (if you don't know Qt.. well doesn't really matter )
    so i can either implement a get, or overload operator*.
    problem is that this exposes the ptr to delete.
    thought about using a reference (which would also help avoid a null or dead ptr), but that would pose a problem for derived classes of the hidden soup.
    also thought about overloading operator delete as a private, but it seems quite inappropriate to overload this scary operator as a semi-hack for "don't touch that" ( which is pretty much the logic i tried to avoid with by not using hidden ctors+friend class as a means to restrict creation..)
    The obvious answer is don't "implement a get" (which is more accurately described as providing a function that provides an unfettered pointer or reference to internal data) nor provide operator *.

    Provide some means in your class (a set of member functions, for example) that allow the user of the class to REQUEST operations. Then only pass on the requests that make sense.

    You seem to be working on a premise that, if an object A contains an object B, then object A must permit access to object B. That is not true. The whole point is often that object A acts as an intermediary that prevents direct access to object B.

    The trade-off is that object A then needs to expose a suitable set of its own operations so it does not need to expose object B. If you are not willing to devote effort to defining such a set of operations, you might as well make the data public (i.e. eliminate the pretence that your class is actually doing any encapsulation).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Sunshine, and read this, this, and this before posting again.

  11. #11
    Registered User
    Join Date
    Aug 2011
    Posts
    6
    Quote Originally Posted by grumpy View Post
    Logic is inconvenient when it contradicts what you want to do.
    funny how fitting your signature is..

    so add methods to the proxy and cancel the operator->..

    say grumpy - what approach you would have taken in my case?

  12. #12
    Registered User
    Join Date
    Jun 2005
    Posts
    6,658
    I wouldn't have tried (in your words) "to prohibit creation without hiding the the constructor + friend keyword" in the first place.

    If I have a contradictory requirement (which appears to be your starting point) I seek clarification in the interests of eliminating contradictory requirements - and hopefully achieve a set of logically consistent requirements.

    I certainly do not jump through hoops and start hacking code to religiously avoid some language feature unless I know there is a good reason to do so.

    Language features are there to be used. Any language feature that has well-defined semantics (such as the friend keyword) is fair game, if it helps achieve a task at hand.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Sunshine, and read this, this, and this before posting again.

  13. #13
    Registered User
    Join Date
    Aug 2011
    Posts
    6
    thanks grumpy,
    hope i didn't get you grinding your teeth there..

  14. #14
    Registered User
    Join Date
    Oct 2006
    Posts
    2,590
    to add to what grumpy said about using language facilities, I'd say that throwing an exception from a constructor is the only (language feature) way to ensure that you can detect that an object was not created. for example operator new throws an exception if it cannot create an object, it is perfectly reasonable to expect your code to behave in the same way.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 12-16-2008, 02:43 PM
  2. Hidden the information --Help!! (T.T)
    By nghoanglinh223 in forum C++ Programming
    Replies: 4
    Last Post: 04-01-2008, 10:07 AM
  3. Hidden board!
    By Queatrix in forum A Brief History of Cprogramming.com
    Replies: 18
    Last Post: 09-04-2006, 03:23 AM
  4. Hidden Columns
    By Gravedigga in forum Windows Programming
    Replies: 2
    Last Post: 09-01-2004, 01:36 AM
  5. Replies: 7
    Last Post: 03-10-2004, 04:10 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21