Jump to content
  • Advertisement
Gnollrunner

C++ Any less ugly and more standard way of doing this?

Recommended Posts

So basically I have pointers to classes that are members of another class. I know for sure they are members and I know their member names.  What I want to do is get a pointer to the class object that contains them. I messed around for a bit and came up with this, but it's ugly.  Anyone know of some better way, or should I just stick with this?

 

#include "pch.h"
#include <iostream>


/**
 #################################################################
 ##  
 #################################################################
 **/

class CClassA 
{

public:

   CClassA(int i) : m_iVal(i) {}

public:

   int m_iVal;

};

/**
 #################################################################
 ##  
 #################################################################
 **/

class CClassC1 : public CClassA

{

public:

   CClassC1() : CClassA(1) {}

};


//################################################################

class CClassC2 : public CClassA

{

public:

   CClassC2() : CClassA(2) {}

};

/**
 #################################################################
 ##  
 #################################################################
 **/

class COwner 

{

public:

   COwner() : m_iTestVal(999) {}

public:

   CClassC1 m_clData1;
   CClassC2 m_clData2;

   int m_iTestVal;


};

/**
 #################################################################
 ##  
 #################################################################
 **/

int main()
{
   COwner clOwner;

   CClassA *pC1 = &clOwner.m_clData1;
   CClassA *pC2 = &clOwner.m_clData2;

   COwner *pOnwer1 = (COwner *)((char *) pC1 - (size_t) &(((COwner *) nullptr)->*&COwner::m_clData1));
   COwner *pOnwer2 = (COwner *)((char *) pC1 - (size_t) &(((COwner *) nullptr)->*&COwner::m_clData2));

   std::cout << "pOnwer1->m_iTestVal       = " << pOnwer1->m_iTestVal << "\n"; 
   std::cout << "pOnwer2->m_iTestVal       = " << pOnwer1->m_iTestVal << "\n"; 

}

 

Share this post


Link to post
Share on other sites
Advertisement

Looks fishy.

I assume you can't influence the "upper class" to simply pass along a pointer when the member is assigned ?

 

Share this post


Link to post
Share on other sites
4 minutes ago, Green_Baron said:

Looks fishy.

I assume you can't influence the "upper class" to simply pass along a pointer when the member is assigned ?

 

It's more of a matter of space. I can do that except it's 8 bytes I have to store and there are 8 of these member classes in each owner class so that's 64 bytes.  There can be millions of these owner class objects so the space usage is very significant.

Share this post


Link to post
Share on other sites

From this current thread, and this one, there is the impression that you are fighting against what C++ is.

C++ tries to enforce encapsulation that you seem to do all your best to destroy and this will undoubtedly lead to (weird) bugs (and probably other undefined behaviors).

So maybe you should ask yourself if you are using the right language. Another option is to find a better way to do it the right way. For example, if you don't have that much 'owners', then storing an uint8 to identify this 'owner' will lead to use few memory compared to store a pointer. You can also use std::map. You can also think again about your design and try to find a better way to solve your current problems.

Share this post


Link to post
Share on other sites

Wow... that's..., really hard to read. If I got it right, you calculate the offset of each member and subtract it from the pointer address. I have to think about it (while I sleep :p) if I can figure out a better way of achieving what you want to do...

Only thing I could come up now is the following:

If you use C++17, and your class ends up having a size of 2^X, you could use alignas to align it in memory.  Then you just calculate the misalignment of the current pointer and correct it to the previous alignment boundary. Wouldn't be that much better I guess, but maybe a little bit.

However, _Silence_ made some good points.

 

Greetings

Share this post


Link to post
Share on other sites
Posted (edited)

Almost looks like you're trying to (re)invent polymorphism.

Also, "clOwner"... Hmm....

Edited by fleabay

Share this post


Link to post
Share on other sites

So leave it as it is then, LOL! .......... Actually I got rid of the *&. That was kind of a cut and paste artifact when I was playing with it.

Share this post


Link to post
Share on other sites

OK here's the cleaner version using multiple inheritance........
 

// TestMuti.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>

class COwner;


/**
 #################################################################
 ##  
 #################################################################
 **/

 class CClassA 
{

public:

   CClassA() : m_iSomeData(888) {}

public:

   int m_iSomeData;

};

/**
 #################################################################
 ##  
 #################################################################
 **/

class CClassC1 : public CClassA
{

public:

   CClassC1() : CClassA(), m_iSomeMoreData(101) {}

   COwner *GetOwner();

public:

   int m_iSomeMoreData;

};

//################################################################

class CClassC2 : public CClassA
{

public:

   CClassC2() : CClassA(), m_iSomeMoreData(102) {}

   COwner *GetOwner();

public:

   int m_iSomeMoreData;

};

/**
 #################################################################
 ##  
 #################################################################
 **/

class COwnerBase
{

public:

   COwnerBase() : m_iTestVal(999) {}


public:

   int m_iTestVal;

};

//################################################################

class COwner : public COwnerBase, public CClassC1, public CClassC2
{
 
public:

   COwner() {}

public:

};

/**
 #################################################################
 ##  
 #################################################################
 **/

COwner *CClassC1::GetOwner()
{
   return static_cast<COwner *>(this);
}

COwner *CClassC2::GetOwner()
{
   return static_cast<COwner *>(this);
}

//################################################################

int main()
{
   COwner clOwner;

   CClassC1 *pC1 = static_cast<CClassC1 *>(&clOwner);
   CClassC2 *pC2 = static_cast<CClassC2 *>(&clOwner);

   COwnerBase *pOnwer1 = pC1->GetOwner();
   COwnerBase *pOnwer2 = pC2->GetOwner();

   std::cout << "pOnwer1->m_iTestVal       = " << pOnwer1->m_iTestVal << "\n"; 
   std::cout << "pOnwer2->m_iTestVal       = " << pOnwer1->m_iTestVal << "\n"; 
}

 

Share this post


Link to post
Share on other sites

And here's an updated version which let's you access your sub-objects as an array which is something I need .........

// TestMuti.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>

class COwner;


/**
 #################################################################
 ##  
 #################################################################
 **/

 class CClassA 
{

public:

   CClassA(int iVal) : m_iSomeData(iVal) {}

public:

   int m_iSomeData;

};

/**
 #################################################################
 ##  
 #################################################################
 **/

class CClassC1 : public CClassA
{

public:

   CClassC1() : CClassA(101), m_iSomeMoreData(101) {}

   COwner *GetOwner();

public:

   int m_iSomeMoreData;

};

//################################################################

class CClassC2 : public CClassA
{

public:

   CClassC2() : CClassA(102), m_iSomeMoreData(102) {}

   COwner *GetOwner();

public:

   int m_iSomeMoreData;

};

/**
 #################################################################
 ##  
 #################################################################
 **/

class COwnerBase
{

public:

   COwnerBase() : m_iTestVal(999) {}


public:

   int m_iTestVal;

};

//################################################################

class COwner : public COwnerBase, public CClassC1, public CClassC2
{

 
public:

   COwner() {}

   CClassA *GetChild(int iIdx)
   {
      return (CClassA *) ((char *) this + s_aOffset[iIdx]);
   }

public:

   static const size_t s_aOffset[2];

};

const size_t COwner::s_aOffset[2] = {
   (size_t) static_cast<CClassC1 *>((COwner *) 8) - 8,
   (size_t) static_cast<CClassC2 *>((COwner *) 8) - 8
};

/**
 #################################################################
 ##  
 #################################################################
 **/

COwner *CClassC1::GetOwner()
{
   return static_cast<COwner *>(this);
}

COwner *CClassC2::GetOwner()
{
   return static_cast<COwner *>(this);
}

//################################################################

int main()
{
   COwner clOwner;

   CClassC1 *pC1 = static_cast<CClassC1 *>(&clOwner);
   CClassC2 *pC2 = static_cast<CClassC2 *>(&clOwner);

   COwnerBase *pOnwer1 = pC1->GetOwner();
   COwnerBase *pOnwer2 = pC2->GetOwner();

   CClassA *pChild1 = clOwner.GetChild(0);
   CClassA *pChild2 = clOwner.GetChild(1);

   std::cout << "pOnwer1->m_iTestVal       = " << pOnwer1->m_iTestVal << "\n"; 
   std::cout << "pOnwer2->m_iTestVal       = " << pOnwer1->m_iTestVal << "\n"; 

   std::cout << "pChild1->m_iSomeData      = " << pChild1->m_iSomeData << "\n"; 
   std::cout << "pChild2->m_iSomeData      = " << pChild2->m_iSomeData << "\n"; 


}

You may be wondering what the 8 is for in "(size_t) static_cast<CClassC1 *>((COwner *) 😎 - 8" ..... With multiple inheritance 0 (i.e. a nullptr) is special. When doing casts C++ checks for it so it doesn't apply the offset you would need if it was a real pointer.  This is so nullptr always stays a nullptr.  In this case however I am trying to do an offset calculation so I want the compiler to change it when I do the cast. Therefor I have to use some other value other than 0 and 8 is a nice round number 😀.  

Share this post


Link to post
Share on other sites
8 hours ago, fleabay said:

Almost looks like you're trying to (re)invent polymorphism.

 

You are right. I would never have seen that :D - probably because I avoid polymorphism as hell 😛

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!