Thread: namespace and data hiding

  1. #1
    C++11 User Tux0r's Avatar
    Join Date
    Nov 2008
    Location
    Sweden
    Posts
    135

    namespace and data hiding

    Hello I have a namespace and two classes. Bar inherits Foo. How can I hide Foo from external usage? One way would be to do it like the following:

    Code:
    namespace Foobar {
    	class Bar {
    		private:
    			class Foo: private Enemy {
    				private:
    					Suit value;
    			} foos[3];
    	};
    }
    I don't want to be able to access Foobar::Foo, But I don't think that's the ultimate way.

    Any suggestions?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Tux0r
    One way would be to do it like the following:
    If you want Bar to inherit from Foo, you cannot have Foo as a nested class in Bar, methinks. A more feasible way would be to declare a namespace mamed detail in the Foobar namespace, then use the convention that this detail namespace contains implementation detail... USE AT YOUR OWN RISK.

    By the way, why do you want to do this?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    C++11 User Tux0r's Avatar
    Join Date
    Nov 2008
    Location
    Sweden
    Posts
    135
    Thanks for your answer.

    Ok the way I'm seeing it now is that I want an array of 3 Foo in Bar and to do that the right way I would have to hide Foo from rest of the program, no one else needs it!

    If I nest another namespace it is still visible to the rest of the program only at another scope.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Tux0r
    Ok the way I'm seeing it now is that I want an array of 3 Foo in Bar and to do that the right way I would have to hide Foo from rest of the program, no one else needs it!
    Oh, so you just want a member array of 3 Foo objects? In that case what you have done is correct.

    Quote Originally Posted by Tux0r
    If I nest another namespace it is still visible to the rest of the program only at another scope.
    Of course, hence this is a convention: a user of your library knows that whatever is in the detail namespace is implementation detail. If he/she uses the constructs found in that namespace, he/she must be prepared for his/her program to break when your library is updated, even when the update is supposed to maintain backward compatibility.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    C++11 User Tux0r's Avatar
    Join Date
    Nov 2008
    Location
    Sweden
    Posts
    135
    Quote Originally Posted by laserlight View Post
    Oh, so you just want a member array of 3 Foo objects? In that case what you have done is correct.
    Yeah but my key point here is: is there a way to have the class Foo in the namespace without it being accessible outside of it? Because I have another base class, Enemy, and I don't see any reason to have it accessible.

    It would be nice if I could use an anonymous namespace to wrap it up with but it does not have the effect I desire.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Tux0r
    Yeah but my key point here is: is there a way to have the class Foo in the namespace without it being accessible outside of it? Because I have another base class, Enemy, and I don't see any reason to have it accessible.
    Not that I know of: the detail namespace convention that I described is the way that I know to address this shortcoming. Besides, namespaces are not closed: even if such a construct existed, your users could theoretically just open your namespace and write whatever they want to easily defeat this access control without modifying any code that you wrote - you would effectively end up with another convention, albeit one that was better supported by language constructs.

    Quote Originally Posted by Tux0r
    It would be nice if I could use an anonymous namespace to wrap it up with but it does not have the effect I desire.
    Not in a header file, at least.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Well when you're talking about access do you mean you want to not have objects of specific classes or that they shouldn't be derived from? Because there are different ways.

    If class A should not be an object because it's nonsensical, then A should be an abstract data type. A will only exist through its children.

    If you want to prevent inheritance the path with least resistance is with a non-virtual destructor. Non-virtual destructors do not properly clean up after a derived object has been sliced, so competent programmers do not extend such classes.

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Come to think of it, I do know a way to accomplish roughly what you want, but it requires you to switch from private inheritance to composition. You could use the pointer to an implementation (pimpl) idiom. Since you only have a forward declaration of Enemy in the header file, your users cannot do much with the Enemy class anyway, but you can do all you want in the corresponding source file.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    C++11 User Tux0r's Avatar
    Join Date
    Nov 2008
    Location
    Sweden
    Posts
    135
    Ok. This is what I think I'll settle down with.

    Code:
    enum class Suit: unsigned char{SPADE,HEART,DIAMOND,CLUB};
    
    class Cards {
    	private:
    		class Card: private Enemy {
    			private:
    				Suit value;
    
    			public:
    				Suit suit() const;
    		} cards[3];
    
    	public:
    		void update();
    };
    
    Suit Cards::Card::suit() const {
    	return value;
    }
    
    void Cards::update() {
    	if(cards[0].suit()==cards[1].suit() && cards[1].suit()==cards[2].suit())
    		delete this;
    }

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Eh, do not use delete this. I believe that it is only defined if the object was created by new, and even then the user has no way of knowing that the object has been destroyed.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    C++11 User Tux0r's Avatar
    Join Date
    Nov 2008
    Location
    Sweden
    Posts
    135
    Three-of-a-Kind - Zeldapedia, The Legend of Zelda wiki - Twilight Princess, Ocarina of Time, Spirit Tracks, and more

    That's the enemy in the game I'm writing, they come in 3 and to defeat them they should be set to the same value.

    When the values of them are the same then the destructor is called. The destructor will call an event. Like, creating a chest with treasure because the enemies were defeated. I believe it makes perfect sense, and because I'm using polymorphism I have to new (afaik).

    Code:
    enum class Suit: char{NONE,SPADE,HEART,DIAMOND,CLUB};
    
    class Cards: private Enemy {
    	private:
    		class Card: private Enemy {
    			private:
    				Suit value;
    
    			public:
    				Suit suit() const;
    				void set_suit(Suit&&);
    				void update();
    		} cards[3];
    
    	public:
    		void update();
    };
    
    Suit Cards::Card::suit() const {
    	return value;
    }
    
    void Cards::Card::set_suit(Suit&& val) {
    	value=val;
    }
    
    void Cards::update() {
    	for(int i{}; i<3; ++i)
    		cards[i].update();
    
    	//Check for equality
    	if(cards[0].suit()!=Suit::NONE && cards[1].suit()!=Suit::NONE && cards[2].suit()!=Suit::NONE) {
    		if(cards[0].suit()==cards[1].suit() && cards[1].suit()==cards[2].suit()) {
    			delete this;
    		}
    		else {
    			for(int i{}; i<3; ++i)
    				cards[i].set_suit(Suit::NONE);
    		}
    	}
    }

  12. #12
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    I find it weird though that when you essentially win no attempt is made to communicate the fact to the outside and your object just dies.

    You should let the scope that created your object be where the object is destroyed wherever possible. Even dynamic storage tends to be managed this way. It mirrors automatic storage, which is easy to understand, and typically is well defined.

  13. #13
    C++11 User Tux0r's Avatar
    Join Date
    Nov 2008
    Location
    Sweden
    Posts
    135
    Ok well there's the other option of adding a bool member variable to Cards, maybe destroyed.

    Then my delete loop on std::vector<Enemy*> will take care of the rest when it's time.

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    C++ does not have the notion of public and private classes as other languages do. If the class is in a namespace and the namespace is visible to the object then the object can use any class in the namespace - generally speaking. You cannot 'hide' classes in namespaces. The only way I know to 'hide' classes is either hide them in the impl of an interface, use pimpl (public functions operate on a private instance of the impl), or do what you have done and make the class private to another. Anytime I see a class nested in another class to me it implies the outside class has ownership of the nested class.

    Another very ugly way to do this is to make a class completely private and then use friend to expose the class to any class needing to use it. Some completely dislike friend as it breaks encapsulation but in this case it is more enforcing encapsulation than breaking it. You are forcing a user of the class to access the nested class members and data via the owning class. One huge problem with friend, even when used appropriately, is that it is not inherited. So any classes derived from a base that has friends does not inherit those friends. This will break a facade pattern rather quickly and does not work well with interfaces.

  15. #15
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Bubba View Post
    Some completely dislike friend as it breaks encapsulation but in this case it is more enforcing encapsulation than breaking it.
    The most common reason I see for people not liking friend is that they believe encapsulation means "everything in a class is accessed via a member function". A more correct definition of encapsulation is that nothing can access private details (data or implementation) of an entity the designer specifically allows such access. A friend declaration is fully compliant with such a definition of encapsulation: it allows a programmer to explicitly grant access to private members of a class.

    Quote Originally Posted by Bubba View Post
    One huge problem with friend, even when used appropriately, is that it is not inherited.
    Allowing inheritence of friendship would completely violate encapsulation (a class could receive access to private data of aniother class without knowledge of the designer of that other class).

    Quote Originally Posted by Bubba View Post
    So any classes derived from a base that has friends does not inherit those friends. This will break a facade pattern rather quickly and does not work well with interfaces.
    It will break broken usages of the facade pattern. There is nothing in the facade pattern that requires the facade to be a friend. Specifically, the facade pattern is not intended as a means of circumventing access control.

    Interfaces specify the semantics for usage of a class. They do not specify how compliance with the interface is implemented. Friendship simply allows a class definition to explicitly specify that other entities (eg other classes or other functions) are part of that interface.

    Or, to put it another way, if inability to inherit friendship breaks the implementation of a derived class then either the design of the base class is broken (i.e. it does not provide access to capabilities required by derived classes) or the derived class implementation is trying to do something invalid (access private members of a base class without permission).

    I suspect you're referring to the fact that poor design of a base can make life inconvenient for implementers of derived classes. That does not mean the derived class implementer should have access to private members of a base class that are not granted by that base class. It means the base class should be modified so it allows the derived class to perform operations it needs.
    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, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. question about a working linked list
    By cold_dog in forum C++ Programming
    Replies: 23
    Last Post: 09-13-2006, 01:00 AM
  2. data validation & namespace
    By tiange in forum C++ Programming
    Replies: 4
    Last Post: 07-05-2005, 02:45 AM
  3. Templated Binary Tree... dear god...
    By Nakeerb in forum C++ Programming
    Replies: 15
    Last Post: 01-17-2003, 02:24 AM
  4. can't insert data into my B-Tree class structure
    By daluu in forum C++ Programming
    Replies: 0
    Last Post: 12-05-2002, 06:03 PM
  5. Post programs
    By GaPe in forum C# Programming
    Replies: 8
    Last Post: 05-12-2002, 11:07 AM

Tags for this Thread