A hack to circumvent access - how bad?

V

Victor Bazarov

Hello,

Please consider the code below. The 'BS/CS/DS' class hierarchy lives in
a third-party library that I can't change. It's broken (a little) in
the sense that I need to call a protected member function of 'BS' from
outside of the hierarchy. The 'A/AA/AAA' is my own hierarchy.

To gain access to 'BS::foo' from 'A::bar', I perform a dirty hack (see
the static_cast). The only hope is that since 'HackBS' contains no data
members of its own, it won't disturb the hierarchy (memory layout, etc).

Oh, there are, of course other members in 'BS' that do not represent an
access problem...

Another thing: we aren't supposed to use virtual or multiple inheritance
for this project.

So, give it to me straight: is this hack a disaster waiting to happen?
So far it "worked" (produced the desired results), although of course
the code has UB, AFAIUI.

--------------------------------------------
#include <iostream>
#include <ostream>

class BS
{
char bs;
public:
BS(char b) : bs(b) {}
virtual ~BS() {}
protected:
virtual void foo()
{ std::cout << "BS::foo(), bs = " << bs << "\n"; }
};

class CS : public BS
{
int cs;
public:
CS(int c) : BS(c % 10 + '0'), cs(c) {}

void foo()
{ BS::foo(); std::cout << " CS :: foo(), cs = " << cs << '\n'; }
};

class DS : public CS
{
double ds;
public:
DS(double d) : CS(int(d*100)), ds(d) {}

protected:
void foo()
{ CS::foo(); std::cout << " DS :: foo(), ds = " << ds << "\n"; }
};

class HackBS : public BS
{
friend class A;
public:
HackBS() : BS(0) {}
};

class A
{
BS* pBS;
public:
void setBS(BS* p) { pBS = p; }
void bar() { static_cast<HackBS*>(pBS)->foo(); }
};

class AA : public A
{
};

class AAA : public AA
{
};

int main()
{
A a;
a.setBS(new BS('z'));
a.bar();

AA aa;
aa.setBS(new CS(42));
aa.bar();

AAA aaa;
aaa.setBS(new DS(3.14159));
aaa.bar();
}
 
V

Vladimir Jovic

Victor said:
Hello,

Please consider the code below. The 'BS/CS/DS' class hierarchy lives in
a third-party library that I can't change. It's broken (a little) in
the sense that I need to call a protected member function of 'BS' from
outside of the hierarchy. The 'A/AA/AAA' is my own hierarchy.

Sounds wrong that you have to call a protected member function. I don't
know details, but are you sure there isn't another way to do what you want?
To gain access to 'BS::foo' from 'A::bar', I perform a dirty hack (see
the static_cast). The only hope is that since 'HackBS' contains no data
members of its own, it won't disturb the hierarchy (memory layout, etc).

Oh, there are, of course other members in 'BS' that do not represent an
access problem...

Another thing: we aren't supposed to use virtual or multiple inheritance
for this project.

So, give it to me straight: is this hack a disaster waiting to happen?
So far it "worked" (produced the desired results), although of course
the code has UB, AFAIUI.

Isn't any UB a disaster waiting to happen?


< code cut >
 
P

Pascal J. Bourguignon

Victor Bazarov said:
Please consider the code below. The 'BS/CS/DS' class hierarchy lives
in a third-party library that I can't change. It's broken (a little)
in the sense that I need to call a protected member function of 'BS'
from outside of the hierarchy. The 'A/AA/AAA' is my own hierarchy.

Protected methods are meant to be used by subclasses.

class YourClass: public DS {
public:
void doSomethingNasty(){
this->foo(); // call the protected method
}
};
 
B

Balog Pal

Victor Bazarov said:
Please consider the code below. The 'BS/CS/DS' class hierarchy lives in a
third-party library that I can't change. It's broken (a little) in the
sense that I need to call a protected member function of 'BS' from outside
of the hierarchy. The 'A/AA/AAA' is my own hierarchy.

To gain access to 'BS::foo' from 'A::bar', I perform a dirty hack (see the
static_cast). The only hope is that since 'HackBS' contains no data
members of its own, it won't disturb the hierarchy (memory layout, etc).

I used similar things to extend/fix MFC classes with nonvirtual member
functions. Sometimes to smuggle out an incorrectly overprotected member too.
And where dealing with "original" instances used simply upcast. Can't recall
a single problem related.

If I wanted to strenghten it, I'd use some assert (possibly static) that
verify the derived class's size is the same and the pointer after the cast
is also the same.
 
M

Maxim Yegorushkin

Victor said:
Please consider the code below. The 'BS/CS/DS' class hierarchy lives in
a third-party library that I can't change. It's broken (a little) in
the sense that I need to call a protected member function of 'BS' from
outside of the hierarchy. The 'A/AA/AAA' is my own hierarchy.

To gain access to 'BS::foo' from 'A::bar', I perform a dirty hack (see
the static_cast). The only hope is that since 'HackBS' contains no data
members of its own, it won't disturb the hierarchy (memory layout, etc).

[]

AFAIK, access specifiers (i.e. private, protected, public) do not affect memory
layout, neither there is a difference in memory layout between class and struct.

Therefore, before including that third-party header just do:

#define class struct
#define private public
#define protected public


And that would effectively disable all member access restrictions.
 
J

Jerry Coffin

[ ... ]
AFAIK, access specifiers (i.e. private, protected, public) do not
affect memory layout, neither there is a difference in memory
layout between class and struct.

Specifiers can (at least theoretically) affect memory layout -- see:

http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thr
ead/1f21a3731a645cab/3f68c6bedded3ce5

for a discussion that covers most of the gory details.

Realistically, however, I'd guess you're right with most compilers
most of the time though.
 
F

Francesco S. Carta

Victor said:
Please consider the code below.  The 'BS/CS/DS' class hierarchy lives in
a third-party library that I can't change.  It's broken (a little) in
the sense that I need to call a protected member function of 'BS' from
outside of the hierarchy.  The 'A/AA/AAA' is my own hierarchy.
To gain access to 'BS::foo' from 'A::bar', I perform a dirty hack (see
the static_cast).  The only hope is that since 'HackBS' contains no data
members of its own, it won't disturb the hierarchy (memory layout, etc)..

[]

AFAIK, access specifiers (i.e. private, protected, public) do not affect memory
layout, neither there is a difference in memory layout between class and struct.

Therefore, before including that third-party header just do:

     #define class struct
     #define private public
     #define protected public

And that would effectively disable all member access restrictions.

I think you could get problems with the first macro if the header
defines some template which use the "class" keyword instead of the
"typename" one. In such a case, the header will fail to compile.

Just my two cents.

Cheers,
Francesco
 
B

Balog Pal

Jerry Coffin said:
Specifiers can (at least theoretically) affect memory layout -- see:

I hoped they do in practice. Th current layout rules leave pretty much
chance to waste space, that can be reduced.
http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thr
ead/1f21a3731a645cab/3f68c6bedded3ce5

for a discussion that covers most of the gory details.

Realistically, however, I'd guess you're right with most compilers
most of the time though.

I would not go with such a drastic solution if I have the 3rd party stuff as
binary+headers, only if there is an ability to compile the library too with
the modifications. (fat chance...)

However, if the pain is only the access right, there's a lighter hack.
Instead of replacing private to public, inserting a line saying

friend struct MyHack;

If the files are allowed to edit, it is an easy insert, and TMK breaks only
theoretic rules. With a little luck it can be piggybacked on keyword
private, or some other text that is known to be in the header via #define.

Like

#define private friend struct MyHack; private

or the same with protected, is worth a try -- certainly it fails if the
keyword is used in the base class list. What really adds to the problem if
the target .h file includes other headers -- though if they use include
guards it may be worked around by pre-inclusion.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top