|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> > How is it encapsulation if everything is public?
> """
> A language construct that facilitates the bundling of data with the methods
> operating on that data.
> """
> Again, it's the definition you pointed to.
Only if you ignore the data hiding part, which is essential for
abstraction.
> > That actually contradicts what you said originally. Originally you said
> > that C++ has *no* encapsulation. Clearly you were drawing a clear line
> > somewhere.
> It has so little encapsulation (in the "restricting access" part of the
> definition) that it might as well not have encapsulation.
You are exaggerating. On purpose.
> In other words, I find that marking something as "private" doesn't give
> significantly more protection to private data than marking something with an
> underline does in Python, in practice. In practice, both are trivial to get
> around, accidentally or on purpose.
You are exaggerating. On purpose.
You can't bypass the access rights in C++ if you want to write a program
which is correct and portable. If you try to bypass it, your program will
not be portable, will be against the standard, and thus incorrect. C++ allows
you to write incorrect programs which will compile and run (on one given
system) for efficiency reasons, but that doesn't make the program correct.
That's a *completely* different thing than having everything public and
only using a naming convention to denote "private" members. If the member
is public, then there will be a 100% correct way of accessing it from the
outside which is not implementation-defined.
There's a huge difference. You make it sound like there was no difference
at all. Just for the sake of argument.
> >> I don't believe that's true. It certainly wasn't in C.
> >
> > What wasn't in C?
> That the standard said there's no guarantees as to which bytes mean what or
> how things are laid out in memory.
I don't think the C standard guarantees how much padding there will be
between members of a struct either. The bit representation of a struct
instance may change from system to system, and even from compiler to
compiler, and hence you must not make assumptions if you want your program
to be portable.
(Moreover, C doesn't guarantee endianess either.)
> > As for the C++ standard, it does certainly not give any guarantees about
> > the bit representation of objects in memory. It's implementation-defined.
> Funky. I was pretty sure at least unsigned had a guarantee that they were
> represented in two's complement binary (e.g., that the bit pattern 0x11 was
> the integer value 3).
An unsigned is not an object, mind you. (We are talking, after all, about
accessing the private members of an object. An unsigned integer has no such
thing.)
Also the standard doesn't guarantee word endianess, so the bit pattern
may actually differ from one system to the next even when we are talking
about unsigned integers.
> >> The elements of a structure are all between
> >> &x and &x + sizeof(x).
> >
> > No, they aren't. The standard doesn't specify how much padding there may
> > be between struct elements. The compiler can add as much padding as it wants
> > (or none at all).
> That doesn't invalidate the formula. I didn't say there was nothing else there.
So you said that "a given type, all by itself, will require sizeof(type)
bytes of memory". Well, duh, that's how sizeof() is defined, after all.
However, the subject in question here is objects and accessing their
private members. You have no portable way of knowing the offset of members
inside objects because their layout is not guaranteed. The first member
might not start from the same address as the object's pointer, and the
amount of padding between members is implementation-defined. Just because
you know that a member requires n bytes of memory doesn't help you much
in resolving its location inside the object.
(That doesn't mean you can't have a pointer pointing to a member of an
object, in a portable way. However, that requires either for the member
to be public or for the object to give you the pointer.)
> > Also, the standard doesn't guarantee that the first member of a struct
> > starts from the same memory address as the struct instance itself. (In
> > practice this can actually differ if the struct has virtual functions.
> > In that case the pointer-to-struct-instance will not point to the first
> > member of the struct. There will be some implementation-dependent vtable
> > pointer there instead.)
> I didn't say that it did.
But we are talking about accessing private members here.
> Wasn't one idea of C++ was that structs without vtables would layout the
> same way as C structures?
But the C standard doesn't give guarantees about padding between members
either, AFAIK.
> In any case, yes, there is, because the class can return a pointer to the
> private variable. You might say "that means it's not private any more", but
> it's still accessing the program's private variables.
Of course if the object exposes the private member in its public interface,
then the outside can have access to it. Returning a reference or pointer to
a member exposes it to the outside.
(There's still the minor difference that it's slightly more abstract than
having the member in the public part of the class in that you could change
the method to return a reference/pointer to something else.)
> (Uh, that *is* legal
> in C++, right? Returning an int* that points to a private instance variable?
> If not, then color me suitably impressed. :-)
It is possible to return a pointer to a member variable. (It's generally
regarded as bad design, though. Returning a const reference is a borderline
case, though. Sometimes used because returning big members by value can be
quite inefficient.)
> >> There's lots of guarantees. And I'm pretty sure that
> >> if you have "struct x {int a; int b} y;" that the standard guarantees
> >> &b > &a.
> >
> > Probably, but if a and b are private, you have no portable way of getting
> > an address to them. You don't know the offset.
> You do inside the class. :-)
"From the outside" implied that the struct doesn't want to expose them.
> And besides, I'm just disputing your assertion
> that the language makes no guarantees about the layout of data.
Well, it doesn't. Not any that would help you accessing them from the
outside if they are unexposed.
(Btw, I didn't mean "doesn't give any guarantees whatsoever". I meant
"doesn't give any guarantees that would help you resolving the address of
a private member from the outside in a portable way".)
> >> Positive integers are represented in twos-complement coding.
> > I'm not completely sure the standard guarantees that.
> >
> >> Unsigned integers occupy the the number of bits indicated by multiplying
> >> sizeof(unsigned) by bits_per_char or whatever the appropriate #define is.
> >
> > Well, duh, because sizeof(type) is *defined* as telling the amount of
> > bytes that the type requires.
> Yes. And then you multiple by bits_per_char to find out the range, which
> means unsigneds don't have padding in the middle, for example.
But if you had, for example, an array of two unsigneds, I'm not sure the
standard guarantees they will be at consecutive memory locations, with no
padding between them. (I could be wrong on this one, though.)
Not that any compiler in the universe would put padding between them,
mind you, but it's probable that the standard doesn't *force* compilers
to not to use padding (eg. because an exotic hardware requires it).
> > That still doesn't help you accessing private data of an object portably.
> That's not what I'm discussing at this point. Besides, you can *access* them
> portably. You can't *interpret* them portably, perhaps, if the structure is
> complicated enough.
Well, if "access" means "reading their bit pattern in memory", then yes,
you can "access" them portably.
> >> Now, if you're going to argue those guarantees don't count, Ok.
> >
> > Don't count to what? The issue was whether it's *well-defined* to break
> > encapsulation in C++. Your own words.
> Don't count the guarantees I listed. You said "C++ makes no guarantess on
> layout" and I listed a bunch it makes.
The context in which I said it implied "no guarantees which would help you
resolve the address of a member variable from the outside".
> And breaking encapsulation is portably accessing private members from
> outside the class. Which I can certainly do using memcpy for example.
What you are using with memcpy is copying the bit pattern of the object
as it is stored in memory. It's arguable whether that's "accessing the
private members" of an object.
To me, accessing means that you actually read (or even write) a private
member variable and write code which depends on it. You can't do that with
memcpy because it doesn't tell you the value of *that* member variable in
question. It only gives you the byte data of the entire object. You can't
start interpreting that byte data in a portable way.
> > It's not well-defined. You can try, but the results are not guaranteed.
> So write(out, &xyz, sizeof(xyz)) where xyz is a class or struct with private
> members might actually crash?
Exactly which member variable did you just access? "All of them" isn't an
answer.
What you did was take the bit pattern of the object in memory and write
it somewhere.
> memcpy(myarray[0], myarray[1], sizeof(myarray[0])) isn't well-defined?
Only in a very limited set of cases, actually. If myarray consists of
class instances, the result is undefined behavior (because you are
bypassing copy constructors).
With basic types it's well-defined, and maybe for PODs with trivial
constructors and destructors.
> There's no meaning for that statement when myarray[0] is a struct with
> private members?
It depends on what kind of constructor/destructor/copy constructor the
struct has.
> Regardless of whether you know which private variable is laid out where,
> you're still "accessing private variables" in ways that more secure
> languages disallow.
Well, C++ doesn't stop you from reading the bytes of an object in memory.
Nobody is denying that.
Whether that constitutes "accessing a private member" is arguable.
> > You mean C++ is causing problems there?
> Oh, you wouldn't believe. Not C++ per se, but unsafe languages in general,
> poorly organized and badly documented.
Safe languages never cause problems, then?
(If I'm to believe thedailywtf.com, I don't think that's the case either.)
> > I suppose I should consider myself lucky in that I get to work in
> > projects where I don't have to go fixing existing code made by incompetent
> > C++ programmers...
> Yep. Well, honestly, the whole development chain is screwed. Not only is the
> code buggy, but the authors are unwilling to fix it, describe it, document
> it, or really take any responsibility at all for its sorry shape.
I'm not sure using a "safe" language would fix those problems either.
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |