2
#include <iostream>

class student
{
    int phone;
    public:
    student(int a)
    {
        phone = a;
    }

};

int main()
{
    class student s1(10);
    printf("%p \n",&s1);
    printf("%d \n",*(&s1));
  //  printf("%d \n", s1.phone);
   // printf("%p",&s1.phone);


    return 0;
}

output: 0x7fffd5aa5abc
10

Can a non member function has access to addresses of class objects? If yes then why cant we have access to its members?

  • 11
    Welcome to undefined behavior land. You lied to you compiler and said `*(&s1)` is an `int` when it isn't. That means it might "work", it also might not. All possibilities are correct. – NathanOliver Nov 05 '19 at 18:23
  • 3
    The printing code for `phone` is commented out. –  Nov 05 '19 at 18:24
  • Where are you trying to access `phone` from the `main`? – Algirdas Preidžius Nov 05 '19 at 18:25
  • *Can a non member function has access to addresses of class objects.* -- You could have done the same tricks here: `std::string s; memset(&s, 0, sizeof(s));` -- You wiped out everything in the string, including whatever `private` member variables were set to. The term `private` doesn't mean "top secret". – PaulMcKenzie Nov 05 '19 at 18:26
  • @AlgirdasPreidžius Just realized that the second one is accessing `phone` in disguise, I think. –  Nov 05 '19 at 18:27
  • 1
    This is not a valid program according to the C++ standard. *Anything* is allowed to happen. Note that C++ has the novel failure mode where asking a compiler "is this a program" has false positives. Just because it *compiles* does *not* in *any way* mean that it is *valid*. You, unfortunately, have to know *all* the rules of the language and abide by them and the compiler can't always help you. And if you break a rule, your program may *silently* misbehave (or worse; *sometimes* do what you want). – Jesper Juhl Nov 05 '19 at 18:28
  • Class access specifiers are meant to be used for correctness, similar to ```const```. Not for airtight security. Your ```main()``` is not accessing a private member variable. – RL-S Nov 05 '19 at 18:29
  • 5
    Access control (`public`, `protected`, `private`) applies to **names**. The code in `main` does not use the name `phone`, so there is no issue involving access. – Pete Becker Nov 05 '19 at 18:37
  • `public`, `protected` & `private` are meant to help you not do silly things. They are not guaranteed protections (and don't exist at run-time). If you get the address of an object and do the proper pointer arithmetic to find the address of a private member, you most certainly can get at it. Should you? No. Can you? Yes. – Jesper Juhl Nov 05 '19 at 18:38
  • Note: instead of `student(int a) { phone = a; }` you *really* want `student(int a) : phone(a) { }`. – Jesper Juhl Nov 05 '19 at 18:45
  • 1
    Also (kind of) aside: The fact that this program compiles but has undefined behavior (although I am sure the compiler will warn you about it, at least if [warnings are enabled](https://stackoverflow.com/questions/57842756/why-should-i-always-enable-compiler-warnings)) demonstrates why `printf` is a bit dangerous if not enough care is taken. If you used the C++ standard library `std::cout <<` from `` instead (and you should), the compiler would tell you at compile time that what you are doing is wrong. (Btw. your includes are wrong, you need `#include` for `printf`) – walnut Nov 05 '19 at 18:47
  • @Chipster "_Just realized that the second one is accessing `phone` in disguise, I think._" How? Undefined behavior is undefined. `*(&s1)` is of type `student`. Which is then printed as `int`, via `printf`, which is undefined behavior. – Algirdas Preidžius Nov 05 '19 at 18:53
  • @AlgirdasPreidžius Well yes, but I mean while the second example doesn't name the member specifically, the behavior the OP is asking about is why the second example is showing the value contained in `phone` anyway. –  Nov 05 '19 at 18:55
  • 1
    Aside: Don't use `class` (or `struct`) in variable declarations as you do in `class student s1(10);`. It is unnecessary (just remove it and it will still work) and can hide or worsen bugs in the program caused by missing (forward-)declarations or name lookup problems. class should (with very rare exceptions) only be used to introduce the definition of a class, in an explicit forward-declaration of a class and in (type) template parameters. – walnut Nov 05 '19 at 18:56
  • @Chipster One cannot reason about specific behavior of undefined behavior. It may work, in the way OP is expecting, on his particular compiler version. The behavior may be different if one used a different version of a compiler, or a different compiler. There are no guarantees about any specific behavior. – Algirdas Preidžius Nov 05 '19 at 18:58
  • If we are able to pass an object in a function call inside a non member function for suppose main(). Does it mean we have access to all the members of object(including private)? – Ahamed Ali Riyaz Nov 05 '19 at 19:04
  • @AhamedAliRiyaz No, not by directly accessing the private members. But as mentioned multiple times, C++ most of the time offers *some* arcane method to circumvent these protections, which if you use imply that you are explicitly taking responsibility for what will happen. – walnut Nov 05 '19 at 19:09
  • so is it like...we have access to address of object but not the addresses of its private members. ex: int *p = & s1.phone;// not valid? – Ahamed Ali Riyaz Nov 05 '19 at 19:12
  • @AhamedAliRiyaz The answers below already go into more detail what the access protection does and does not do. If you need clarification on something, you should probably comment on the relevant answer. – walnut Nov 05 '19 at 19:15
  • Try doing it with `-Wall -Wextra -Werror` But printf() is expecting an integer `%d` you lied to it but it does not check the type (because this is a C function what do you expect). – Martin York Nov 05 '19 at 23:06

5 Answers5

2

Can a non member function has access to addresses of class objects? If yes then why cant we have access to its members?

You have common misunderstanding. Data encapsulation (as other tools like const correctness) is a tool that helps you to write better programs ie have less errors. It is not a jail or a watchdog that would try to make it impossible. You want to ruin your ability to manage complexity of your program - go ahead, make all members public, do not use const qualifiers and so on. If you want to use these tools - they will be your friends. It means normally you try to access that data when you should not - compiler will remind you that you do something wrong, so you can fix your error. It does not mean that it will monitor memory and magically restrict your access to it.

Slava
  • 43,454
  • 1
  • 47
  • 90
  • int *p = &s1.phone// is it valid? Do we have access only to address of object but not the addresses of its private members? – Ahamed Ali Riyaz Nov 05 '19 at 19:20
  • @AhamedAliRiyaz in what context? Outside of a member or friend? No it is not valid, but you can make a member that will return that address or you can simply make that member public. Again compiler will control legitimate way you access that data, you try hacky way or sharing pointers around, it will not stop you. – Slava Nov 05 '19 at 19:26
1

Can a non member function has access to addresses of class objects?

Yes. The address of an object is not protected by any access specifier.

If yes then why cant we have access to its members?

You can't access the name phone outside the class because it is private.

Technically, that doesn't prevent the member object from being accessed though.


printf("%d \n",*(&s1));

%d format specifier requires the argument to be an int. *(&s1) which refers to the object named by s1 is not an int, which violates that precondition, and as a consequence the behaviour of the program is undefined.

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

You have to write at least like

printf("%d \n",*reinterpret_cast<int *>(&s1));

A padding can not be at the start of this class with the single non-static data member. So the address of the class is equal to the address of its single data member.

In fact you are not dealing directly with the private data member. You are just reinterpreting a memory. In general at the first address of a class there can be anything if a class for example is not a standard-layout type.

Pay attention to that according to the C++ Standard the order of allocation of non-static data members with different access control is unspecified. So for example if you will add for example a public pr protected data member to your class then it is not necessary that using the trick with the class address you will output the private data member.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    *padding may not be at the start of a class* This is only true for standard layout classes. For any other class this code is UB: https://stackoverflow.com/questions/30617519/reinterpret-cast-from-object-to-first-member – NathanOliver Nov 05 '19 at 18:27
  • @NathanOliver-ReinstateMonica In the provided example the class has only one non-static data member. So what are you going to append to the beginning of the class? – Vlad from Moscow Nov 05 '19 at 18:31
  • 1
    Nothing. Your statement, at least as it reads, makes it seem like a class can never have padding. I'm pointing out that that isn't true. – NathanOliver Nov 05 '19 at 18:32
0

If private members of a class cannot be accessed by a non member function then how come main() is able to print value of phone in this program?

It still can't. Consider the following code:

printf("%d \n", s1.phone);

This won't compile because phone is "private in this context." You can't access private member variables directly.

Why this is "working" is because printf is trying to treat your student as an int. Because the memory stored at that location is presumably 10 (because of memory layout, etc.), this appears to be working. However, you are still not accessing a private member, you are casting to an int and tricking, so to speak, your compiler.

Note that doing this is undefined behavior, so don't do it. Playing with undefined behavior is really bad.

  • It is better now, but you removed the important note about undefined behavior for some reason. Now it seems as if this method was a legitimate way of doing things. – walnut Nov 05 '19 at 19:31
  • I did because I'm not exactly sure if casting to an int is UB. If it is getting treated as an `int` by `printf`, then is that UB? –  Nov 05 '19 at 19:33
  • Yes it is, first because the specification of `printf` explicitly says that you *must* pass the correct type and second because even if it didn't a variadic function (such as `printf`) cannot access an argument of one type expecting it to be a different incompatible type (here given by the `printf` format string). The types here are incompatible already because one is a structure and the other is not. The only way to do this cast is by using `reinterpret_cast` to cast before passing and being very careful that it actually does the right thing, see VladfromMoscow's answer and comments below it. – walnut Nov 05 '19 at 19:37
  • Thanks. Added it back in, and even found a relevant link supporting what you said. –  Nov 05 '19 at 19:49
0

class declaration defines a new complex data type that encapsulate one or more data members in one memory block called object. when you try to access certain member inside that object the complier calculate the correct offset and adds it to the address of the object. so in your code your private member at the beginning of the class declaration so its offset is 0 yields to same object address. note this will not be true if you class has virtual functions or inherits form another class

access modifiers helps you to design better code but doesn't generate any protection to the data memory

Ahmed Anter
  • 650
  • 4
  • 13