0

Inside main.cpp

class vivek
{
    int i;
    float d;
public:
    vivek()
    {
        i = 4;
        d = 4.44;
    }
    ~vivek()
    {
        cout << "destructor" << i;
    }
    int get()
    {
        return i;
    }
};

int main()
{
    vivek *viku = new vivek;
    vivek *p;

    p = viku;
    cout << (*(int*) (p));
    getchar();

    return 0;
}

Through above code i can able to access variable i , but i want to know how can i access the variable d .

I know this concept shall not be advisable since it violates encapsulation .. But i just want to know how we can do this ?

Viku
  • 2,845
  • 4
  • 35
  • 63
  • 7
    You cannot. (You cannot even do what you are doing right now; you were unlucky that it worked) Why would you want to? – R. Martinho Fernandes Nov 27 '12 at 13:53
  • You cannot. That's the whole point. It's none of `main`'s business. Also, you have a massive memory leak. – Kerrek SB Nov 27 '12 at 13:59
  • @R.MartinhoFernandes Actually, they *can* do what they're doing right now. `vivek` is a standard-layout struct, and so, as per [class.mem] point 20, "A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member ... and vice versa." – Angew is no longer proud of SO Nov 27 '12 at 14:02
  • just in one of my interview they had asked me to get the value of d . I know in our programming world , we never use this .Is there any way to access variable d like variable p has been accessed ? – Viku Nov 27 '12 at 14:04
  • @Angew oh, you are right. I thought that was for trivially copiable. – R. Martinho Fernandes Nov 27 '12 at 14:08

6 Answers6

2

While it's extremely hacky, it is possible, because vivek is a standard-layout struct. This means you can do this:

#include <iostream>

// copied from original
class vivek {
  int i;
  float d;
public:
  vivek() {i = 4; d = 4.44; }
  ~vivek() { cout<<"destructor"<<i; }
  int get() { return i; }
};

struct vivek_sneaky_accessor {
  int i;
  float d;
};

int main() {
  vivek v;
  vivek_sneaky_accessor *acc = reinterpret_cast<vivek_sneaky_accessor*>(&v);
  std::cout << acc->d;
  return 0;
}

This relies on [class] points 7 and 8 (definition of standard-layout struct) and on [class.mem] points 17 and 20 (layout-compatibility of standard-layout structs).

Disclaimer I am in no way advocating this as a reasonable thing to do. I am just saying that it is actually possible.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
2

I'll risk downvotes becase i think you are doing it to understand pointers.

Maybe , what you were expecting was something like this :
int * x=reinterpret_cast<int *>(p);
x++;
cout<<*reinterpret_cast<float *>(x);

Which works, and probably will work on most of the compilers you come across. However, there are many reasons why you must not be doing something like this.

Uses and Abuses of Access Rights is a must read.

Also note that the standard clearly comments on the order of members separated by access specifier. From another sof answer :

Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1)

Community
  • 1
  • 1
axiom
  • 8,765
  • 3
  • 36
  • 38
  • 1
    You take address of the object in an int pointer. Add 1 to it so that it is incremented by sizeof(int). Now you have address of the memory location just next to it. You cast it into a float pointer and print value. You'll get the result. However try running it after reading the article :) – axiom Nov 27 '12 at 14:28
  • +1 A short concise answer. Will this behavior change when the class is part of a dynamic polymorphic inheritance tree? – daramarak Nov 27 '12 at 14:48
  • Try doing this with a double instead of a float and tell me if it still works. The fact that the order is defined does not make the position defined. – R. Martinho Fernandes Nov 27 '12 at 15:22
  • @daramarak yes, this will stop working when that happens. It will also stop working with less radical changes, like making the second member be of a type that has a stricter alignment than int, like double on most implementations. – R. Martinho Fernandes Nov 27 '12 at 15:49
  • @R.MartinhoFernandes . Yes , it still works on my machine. However, i must emphasize here that i never said this is something that should be done, or will work always. – axiom Nov 27 '12 at 16:30
1

In class vivek

public:
  float getD() {
    return this -> d;
  }

And invoke it in your code like this:

std::cout << (p -> getD()) << std::endl;
hinafu
  • 689
  • 2
  • 5
  • 13
1

If you want/need to access them, make them public. That's the point of public, it means the user of the class is allowed to see and change the things that are public.

Someone will probably tell you that this "breaks encapsulation." However, if you just need the class to hold a few values, and you don't need to do anything fancy, making data members public is not an issue.

Dan
  • 12,409
  • 3
  • 50
  • 87
  • The problem is that classes that just hold a few values tend to grow over time. Before you know it you have a large class with complex logic, whose data members are accessed directly in many parts of your code, resulting in a tangled mess. Always making your data members private is a good rule of thumb. – Dima Nov 27 '12 at 14:29
  • To me that sounds like overengineering at the start and underengineering when growing. A much better rule of thumb is to actually have class invariants. If public members are fine for holding those invariants, then any change you do in the future that requires non public members is a breaking change. Breaking changes that break code at compile-time are better than those that compile silently. – R. Martinho Fernandes Nov 27 '12 at 15:17
1

At the risk of being down-voted by language lawyers, here is a bit of hacker's advice for you in hope that it might be interesting. Private members are not meant to be accessed from outside of the class and class's friends. However, if you absolutely must access those member fields of the class, a hack like this could work:

#include <iostream>

class vivek {
    int   i;
    float d;

  public:
    vivek() : i(4), d(4.44) {}
    ~vivek() {}
};

int main()
{
    vivek viku;
    struct badhack {
        int   i;
        float d;
    } *h = (sizeof(badhack) == sizeof viku ? (badhack*)&viku
            : ((badhack*)((char*)&viku + sizeof(void*))));
    std::cout << "i=" << h->i << ", d=" << h->d << std::endl;
}

Note the game with sizeof's — that is just an example of determining a virtual table that takes sizeof(void*) bytes and is a first implicit field in the class shall there be any virtual members. If you do not do that and a class happens to have a virtual table, then data offsets will get screwed up and the trick won't work, so that's why we adjust offset by sizeof(void*) bytes in order to avoid that problem. Now, this is not defined by the standard and is compiler-specific, but I have never ran into a compiler that implements virtual tables differently as this is the most efficient way.

Another option would be as simple as this:

#include <iostream>

#define class struct
#define private public

class vivek {
    int   i;
    float d;

  public:
    vivek() : i(4), d(4.44) {}
    ~vivek() {}
};

int main()
{
    vivek viku;
    std::cout << "i=" << viku.i << ", d=" << viku.d << std::endl;

    return 0;
}

Note, however, that above most likely will not work for member functions. Compilers these day are smart and mangle function names differently depending on their access level.

And please do not use tricks like these unless it is necessary to save someone's life and you are willing to sacrifice yours in return.

0

While it is certainly possible to treat your object as a sequence of bytes and fiddle with those bytes directly, it is a very bad idea. The whole point of having classes and objects is to save you the trouble of having to think about how the data are actually laid out in the memory.

Dima
  • 38,860
  • 14
  • 75
  • 115