开发者

When can I access an object member directly in memory? No getters called

开发者 https://www.devze.com 2023-03-04 07:34 出处:网络
It is usually allowed to do something like that (no comments on the code please :-)) class SimpleClass {

It is usually allowed to do something like that (no comments on the code please :-))

class SimpleClass {
    int member;
};

SimpleClass instance;
int* pointer = (int*) &instance;

However, if I define my class as:

class SimpleClass {
    virtual void foo();
    int member;
};

I can't do that anymore. Well, I guess I can, of course; it's just more complex.

So I was wondering: is it s开发者_如何学Goomewhere specified, or the only way to know when I can do that is just to use some common sense? Not counting alignment issues, which can usually be solved


Generally you want to keep the innards of a class of closed off from the outside world as you can, but if you do need to access a member directly simply specify it as public and take a pointer directly to it.

class SimpleClass {
public:
  int member;
};

SimpleClass instance;
int* pointer = &instance.member;

I would avoid accessing the members in the way you describe because as you noted small changes in the class can mess it up, which may be fine whilst you are writing the code but when you come back to it much later you will probably overlook such subtleties. Also unless the class is constructed entirely of native data types, I believe the compiler's implementation will affect the required offset as well.


You can only do this safely if your class is plain old data (POD). From Wikipedia:

A POD type in C++ is defined as either a scalar type or a POD class. A POD class has no user-defined copy assignment operator, no user-defined destructor, and no non-static data members that are not themselves PODs. Moreover, a POD class must be an aggregate, meaning it has no user-declared constructors, no private nor protected non-static data, no base classes and no virtual functions. The standard includes statements about how PODs must behave in C++.

See this page for many details on POD types. In particular,

"A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member ... and vice versa" [§9.2, ¶17].


class SimpleClass {
    int member;
};

SimpleClass instance;
int* pointer = (int*) &SimpleClass;

In the above code pointer points to SimpleClass::member and hence you can access SimpleClass::member in this way.

Once you add an virtual method to the class SimpleClass, the memory map of the object changes.

class SimpleClass {
    virtual void foo();
    int member;
};

Every object of SimpleClass now contains a special pointer called as vptr which points to a vtable which is a table of addresses of all virtual functions in SimpleClass. The first 4 bytes of every object of SimpleClass now point to the vptr and not SimpleClass::member and that is the reason you cannot access member in the same way as first case.

Ofcourse, virtual behavior is implementation detail of compilers and vptr nor vtable are specified in the standard but the way i mentioned is how most compilers would implement it.

Since the implementation detail might be different for each compiler you should rely on accessing class members through pointers to class(especially polymorphic classes). Also, doing so defeats the entire purpose of Abstraction through Access Specifiers.


All right, several things.

Your first code example won't compile because you can't have a pointer to a class. I think you meant this:

SimpleClass instance;
int* pointer = (int*) &instance;

(Please don't code you haven't tried compiling.)

This kind of casting is powerful and dangerous. You could just as well cast to a pointer to some type (say, char*) and as long as it was a type no larger than int, the code would compile and run. This kind of reinterpretation is like a fire axe, to be used only when you have no better choice.

As it is, pointer points to the beginning of 'instance', and instance begins with instance.member (like every instance of SimpleClass), so you really can manipulate that member with it. As soon as you add another field to SimpleClass before member, you mess up this scheme.

In your second code example, you can still use pointer to store and retrieve an int, but you're doing so across boundaries within the memory structure of instance, which will damage instance beyond repair. I can't think of a good metaphor for how bad this is.

In answer to your questions: yes, this is specified somewhere, and no, common sense isn't good enough, you'll need insight into how the language works (which comes from playing around with questions like this).

0

精彩评论

暂无评论...
验证码 换一张
取 消