0

I know that as far as good programming practices go this is a bad idea, but I've been trying to solve a relatively difficult problem and was hoping for some insight. Essentially I'm trying to output all members of a class as follows:

class protoCalc
{
    private:
        int x; 
        int y;
        virtual int basicAddition()
        {
            return x + y;
        }
        virtual int basicMultiplication()
        {
           return x*y;
        }
public:
    protoCalc(){
        x = 14;
        y = 120;
    }
};

Accessing x and y proved easy enough; to do so I wrote a function (included my thoughts as to how this works, whether they're correct or not):

int private_member_Print(void* proto)
{
    protoCalc* medium = (protoCalc*)proto;
    protoCalc halfway = *medium;
    int* ptr = ((int *)(&halfway));
return ptr[1];

}

The above will return the value of x, if ptr[2] is used it will return the value of y.

Now I have two questions, the first being what is ptr[0] pointing to? Shouldn't that bit of memory be occupied by the private member x seeing as that's the first member of class protoCalc? If not, then what does occupy this address?

Secondly, how do I access the virtual functions? My first intuition was that address ptr[3] would be occupied by the basicAddition() virtual function and ptr[4] the basicMultiplication() function, however this is not the case. When this failed to be true my next thought was that ptr[0] contained the pointer to the location of the virtual member table that held the two functions I was seeking. However, this also proved to be false.

So how do I access these virtual functions outside of the class as I have accessed the private members x and y? Obviously I could change the circumstances to make it easier, but that would defeat the purpose of the problem.

manlio
  • 18,345
  • 14
  • 76
  • 126
  • This is all undefined behaviour. Provide public functions for accessing private members if that's what you want to do. – Jonathan Potter Nov 02 '14 at 05:45
  • 2
    As soon as I see a void pointer and a cast I stop reading. Whatever follows will not be good for my brain. – Neil Kirk Nov 02 '14 at 05:51
  • Least of your concerns, but your functions could be made const. And if a class has virtual functions, it should probably have a virtual destructor. – Neil Kirk Nov 02 '14 at 05:51
  • I must have not been particularly clear about the setup of the problem. The only code I can modify is within my "private_member_Print" function. Everything within the class must stay as is for the purpose of the solution – LilLarryboy Nov 02 '14 at 05:53
  • 1
    In practice `ptr[0]` probably points to the virtual function table pointer, but you can't rely on that. http://stackoverflow.com/questions/10925115/location-of-virtual-function-table-pointer-in-object – Neil Kirk Nov 02 '14 at 05:53
  • All of this depends on so many factors, like the compiler, the platform, the allocation method for your object and a gazillion others – Eric Nov 02 '14 at 06:39

1 Answers1

0

What you are currently doing is undefined behavior. The layout of an object in memory is left up to the compiler, in most cases, and you have no idea where a compiler will place each member in memory.

That being said, there is a way to implement this is you heavily abuse templates. I would highly recommend not doing this and instead provide member functions to access the required data.

Here is an example of this in action.

#include <iostream>

class Priv {
private:
    int i;
    void print( ) {
        std::cout << i << std::endl;
    }

public:
    Priv( ) : i( 100 ) {}

    void print_pub( ) {
        std::cout << "Public" << std::endl;
        this->print( );
    }
};

template<typename Tag>
struct result {
  /* export it ... */
  typedef typename Tag::type type;
  static type ptr;
};

template<typename Tag>
typename result<Tag>::type result<Tag>::ptr;

template<typename Tag, typename Tag::type p>
struct rob : result<Tag> {
  /* fill it ... */
  struct filler {
    filler() { result<Tag>::ptr = p; }
  };
  static filler filler_obj;
};

template<typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;

struct Priv_f { typedef void ( Priv::*type )(); };
template class rob< Priv_f, &Priv::print >;

struct Priv_i { typedef int Priv::*type; };
template class rob< Priv_i, &Priv::i >;

int main( ) {
    Priv p;

    (p.*result<Priv_i>::ptr) = 1;
    (p.*result<Priv_f>::ptr)(); 

}

An explanation of the rob/result template classes can be found here. It should work across compilers.

Smith_61
  • 2,078
  • 12
  • 12
  • I think the question is more focused on how virtual functions are implemented. You attempt to cover that, but not entirely correctly: it's not implementation-defined. Implementations are not required to document how they implement virtual functions, nor how they lay out classes. The rest may be relevant to what the OP is asking, but not at all to what the OP is interested in, I think. –  Nov 02 '14 at 10:11
  • In fact, the OP's comment "The only code I can modify is within my "private_member_Print" function." quite explicitly discards this approach. –  Nov 02 '14 at 10:13
  • Yes, I do know there are much easier ways to approach what I'm trying to accomplish which is why I mentioned such in the primary question :D. I use visual studio and through trial and error have discovered that ptr[0] does contain a pointer to the vtable, however the problem I'm struggling with now is trying to discover how to access information from the vtable – LilLarryboy Nov 02 '14 at 16:07
  • @hvd I was under the impression that implementation defined meant the implementation is left to decide how things are laid out in memory. Not that it was required to be documented. I may be wrong though. – Smith_61 Nov 02 '14 at 17:35
  • @Smith_61 Implementation-defined means the implementation is required to documenting it. What you say could be a sensible meaning of the term, it just happens not to be the meaning used in the C++ standard. When the implementation is required to make a choice, but not required to document that choice, that's called "unspecified". –  Nov 02 '14 at 21:09
  • @hvd Okay, my mistake. I will edit it to change that. – Smith_61 Nov 03 '14 at 00:25