Thread: Class access enforcement

  1. #1
    Registered User Chris87's Avatar
    Join Date
    Dec 2007
    Posts
    139

    Class access enforcement

    I'm told by my friend at Apple that C++ classes don't really enforce private/protected access and that all I'd need is a pointer to an instance of the class to access everything. He said it was mainly to prevent screwing up on my part as the developer, and also that Java, for example, strictly enforces it.

    I have to ask though. Is there a way to enforce this in C++ using GCC, if not a non-compiler-specific workaround, or am I out of luck?

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Your friend at Apple doesn't know what he or she is talking about.

    If you want an example;
    Code:
    class X
    {
        public:
            int x;
        protected:
            int y;
        private:
            int z;
    };
    
    int main()
    {
         X variable;
         variable.x = 5;   // OK:  modifying public member
        
         variable.y = 10;  // trigger a compiler error due to attempt to access protected member of X
    
         variable.z = 15;  // trigger a compiler error due to attempt to access private member of X
    
    
          //  now do the same with a pointer
    
         X *p = &variable;   //   make p point at a valid object
    
         p->x = 5;   // OK:  modifying public member
        
         p->y = 10;  // trigger a compiler error due to attempt to access protected member of X
    
         p->z = 15;  // trigger a compiler error due to attempt to access private member of X
    }
    There are various techniques to deliberately circumvent the above, but they all involve some form of undefined behaviour (i.e. there is no guarantee they will give the same result for different compilers). If you deliberately use those techniques (and it is unlikely you will use them accidentally) you accept the consequences.
    Last edited by grumpy; 03-07-2009 at 10:26 PM.

  3. #3
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    In C++, if a programmer is determined to misuse specific data, the language always provides the power to do that.

    However, You can hide the structure of a class form the programmer so that he doesn't know what he's modifying, and you can hide the implementation of functions in linkable libraries.

    Private/protected mode is not a security feature, but a tool for the developer to orgonise code. This is as true in Java as it is in C++. So preventing the developer from doing what he is determined to do is not useful to the developer. As long private data and functions are used traditionally, requiring all contrairy to intent statements to be explicitly stated through casting is sufficient. It ensures that privateness is enforced precicely when the developer want it to be enforced.

    I suppose that as private data can be used as a security feature in java though serialized classes, but a determined developer can circumvent that by modifying his JVM, or writing his own de-serializer. So other security methods are preferred.
    Last edited by King Mir; 03-07-2009 at 10:41 PM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  4. #4
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    re:grumpy

    I agree with grumpy your friend at Apple probably doesn't know what he's talking about. He is however technically right in his assertion. However, he is wrong in thinking that this is a drawback of C++.

    Here is an example of a well defined breaking of privatisation:
    Code:
    class T
    {
      int x;
      public: 
      const int &getX(){
        return x;
      }
    }
    
    void func(){
        const_cast<int&>( T().getX() ) = 1;
    }
    Here you are violating the privacy contract of class T, but the result is guaranteed to work, because of the nature of cost_cast.

    By the way, DON'T DO THIS.
    Last edited by King Mir; 03-08-2009 at 06:34 PM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  5. #5
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by King Mir View Post
    Here is an example of a well defined breaking of privatisation:
    Code:
    class T
    {
      int x;
    
      const int &getX(){
        return x;
      }
    }
    
    void func(){
        const_cast<int>( T().getX() ) = 1;
    }
    Here you are violating the privacy contract of class T, but the result is guaranteed to work, because of the nature of cost_cast.
    Not true.

    If we address the fact that your example won't compile (you need to make getX() public, and the const_cast needs to be to an int&).....

    The const_cast is accepted by the compiler, but the result of using the non-const reference to modify the underlying variable yields undefined behaviour. In practice, it may work as you expect, but there is no absolute guarantee it will.
    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.

  6. #6
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    The following GotW link will tell you absolutely everything you need to know about this:
    http://www.gotw.ca/gotw/076.htm
    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"

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    "C++ tries to protect against Murphy, not Machiavelli."

    You can subvert just about everything C++ does simply by using raw pointers. At the same time, the sheer ugliness of such code should alert you that you're doing something wrong. If you still persist in doing it, that's your fault alone, and not that of C++. The enforced access system is there to prevent mistakes, not abuse.

    On the flip side, unless you're in a restricted security sandbox, you can easily subvert Java's access rules. Object-relational mappers and unit test frameworks do it on a regular basis.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by grumpy View Post
    The const_cast is accepted by the compiler, but the result of using the non-const reference to modify the underlying variable yields undefined behaviour. In practice, it may work as you expect, but there is no absolute guarantee it will.
    The standard guarantees that if the value was not originally const, that the modification is well defined.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  9. #9
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by King Mir View Post
    The standard guarantees that if the value was not originally const, that the modification is well defined.
    Yeah; the difficulty lies in determining if the value was originally const. In your example you gave above, T() is a temporary, and temporaries are inherently const during their lifetime (from the point of return from their constructor until the point of entry to their destructor). Try passing a temporary object to a function that accepts a non-const reference.

    Yes, there are cases where const_cast<> can be used to discard constness, and the resultant pointer/reference can be used to modify the underlying object in a well-defined manner. In my experience (which I concede is not an absolute measure of common practice) the majority of cases where programmers use const_cast to discard constness do not fall into those narrow cases. The most common case I've seen is to hack a class that does not supply an appropriate setter function. const_cast is then used to subvert a getter that returns a const reference. The problem with that, practically, is when other member functions of the class assume that the affected data is fixed and the functioning of the class can be compromised - particularly if some member functions maintain a copy of the data, derive the same value in another way, or rely on the value being in some specified range that gets subverted. And the programmers involved defended the practice using the argument that "const_cast is well-defined".
    Last edited by grumpy; 03-09-2009 at 01:57 AM.
    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.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by grumpy View Post
    Yeah; the difficulty lies in determining if the value was originally const. In your example you gave above, T() is a temporary, and temporaries are inherently const during their lifetime (from the point of return from their constructor until the point of entry to their destructor). Try passing a temporary object to a function that accepts a non-const reference.
    No, they aren't. You can't bind temporaries to non-const references, but that's because the changes wouldn't be visible, so the rule is there to catch mistakes. But temporaries aren't inherently const. For example, you can call a non-const member function of the temporary, and it can easily modify the object:
    Code:
    struct S {
      int i;
      void f() { i = 100; }
    }
    
    int main()
    {
      S().f();
    }
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Meh, temporaries are r-values and the compiler simply won't allow you to bind them to non-const variables without tricks (but they are not const).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by grumpy View Post
    Yeah; the difficulty lies in determining if the value was originally const. In your example you gave above, T() is a temporary, and temporaries are inherently const during their lifetime (from the point of return from their constructor until the point of entry to their destructor). Try passing a temporary object to a function that accepts a non-const reference.

    Yes, there are cases where const_cast<> can be used to discard constness, and the resultant pointer/reference can be used to modify the underlying object in a well-defined manner. In my experience (which I concede is not an absolute measure of common practice) the majority of cases where programmers use const_cast to discard constness do not fall into those narrow cases. The most common case I've seen is to hack a class that does not supply an appropriate setter function. const_cast is then used to subvert a getter that returns a const reference. The problem with that, practically, is when other member functions of the class assume that the affected data is fixed and the functioning of the class can be compromised - particularly if some member functions maintain a copy of the data, derive the same value in another way, or rely on the value being in some specified range that gets subverted. And the programmers involved defended the practice using the argument that "const_cast is well-defined".
    I totally agree that the example I posted is bad code. I said as much when I posted it. It is however, well defined. This means that it is a very bad hack, not simply incorrect.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Visual Studio - Access PictureBox outside Form1 class?
    By andreasleon in forum C# Programming
    Replies: 1
    Last Post: 06-08-2009, 01:55 PM
  2. deriving classes
    By l2u in forum C++ Programming
    Replies: 12
    Last Post: 01-15-2007, 05:01 PM
  3. Message class ** Need help befor 12am tonight**
    By TransformedBG in forum C++ Programming
    Replies: 1
    Last Post: 11-29-2006, 11:03 PM
  4. class access
    By Unregistered in forum C++ Programming
    Replies: 1
    Last Post: 01-24-2002, 08:00 AM
  5. implicit constructor and class access
    By Clarinetster in forum C++ Programming
    Replies: 1
    Last Post: 11-22-2001, 03:59 PM