interface problem in gcc

S

sojalvo

Hi,
I'm porting a project from Win32 to Linux(debian) and I found a problem
using interfaces.
For simplify the question, I created a small test and here is the code:
#include <stdio.h>
#define interface struct
interface ITest
{
virtual int printHello() = 0;
protected:
virtual ~ITest(){};
};

class CTest : public ITest
{
public:
CTest(){ }
virtual ~CTest() { }
private:
//ITest Interface
int printHello() { printf("Hello\n"); }
};

class CGetter
{
public:
CGetter() { test = new CTest; }
~CGetter() { delete test; }
void getTestPtr(const ITest*& t) const;
private:
CTest * test;
};

void CGetter::getTestPtr(const ITest*& t) const
{
t = test;
return;
}

int main( int argc, char *argv[] )
{
ITest * it;
CGetter g;
g.getTestPtr((const ITest*) it);
it->printHello();
return 0;
}

The problem is with the "it" pointer in main.
Debugging the CGetter::getTestPtr() fnc. I can see:
"test" pointer address = (CTest *) 0x8049c20
after a assignment,
"t" pointer address = (const ITest *&) @0xbffff88c: 0x8049c20
and back in main,
"it" pointer address points to: (ITest *) 0x4023f620
causing segmentation fault.
In Win32 this test works... Any Idea?

Thanks,
 
D

Dietmar Kuehl

sojalvo said:
class CGetter
{
public:
void getTestPtr(const ITest*& t) const;
};
ITest * it;
CGetter g;
g.getTestPtr((const ITest*) it);

Any compiler accepting this code is wrong: the result of the cast
is a temporary which is bound to a non-const reference. It is illegal
to bind temporaries to non-const references.

Apparently both compilers you tried got this wrong and illegally
compile your code. One chooses to actually pass a reference to
the original pointer (the Windows compiler you are using) and one
opted to create a true temporary object and pass this one to your
function. The net effect is that the assignment in 'getTestPtr()'
had an effect for one compiler but not the other, causing the code
to fail in situation.

In addition, your C style cast is also illegal! You cannot pass
a pointer to a non-const object to a function taking a reference
to a const object: assigning a pointer to a const object to the
reference would yield a non-const access path the object. This is,
of course, illegal! Your compiler would probably have warned you
about this problem if had used appropriate new-style casts (which
would, of course, have prohibited doing what you apparently tried
to do). You should declare your pointer 'it' properly in the first
place:

| ITest const* it = 0;
| CGetter g;
| g.getTestPtr(it);
Debugging the CGetter::getTestPtr() fnc. I can see:
"test" pointer address = (CTest *) 0x8049c20
after a assignment,
"t" pointer address = (const ITest *&) @0xbffff88c: 0x8049c20
and back in main,
"it" pointer address points to: (ITest *) 0x4023f620
causing segmentation fault.

You should have looked at the address of 'it' ('&it'), too: I'd
bet that it gives a different value than '0x4023f620'.
In Win32 this test works... Any Idea?

What do you mean by "works"? The code yields undefined behavior, i.e.
it does whatever it decides to do (of course, the compiler should
have rejected it in the first place). The effect may be what you had
expected but it may also be something entirely different.
 
V

Victor Bazarov

sojalvo said:
I'm porting a project from Win32 to Linux(debian) and I found a problem
using interfaces.
For simplify the question, I created a small test and here is the code:
#include <stdio.h>
#define interface struct
interface ITest
{
virtual int printHello() = 0;

It probably should be 'const':

virtual int printHello() const = 0;
protected:
virtual ~ITest(){};
^
Extraneous semicolon.
};

class CTest : public ITest
{
public:
CTest(){ }
virtual ~CTest() { }
private:
//ITest Interface
int printHello() { printf("Hello\n"); }

And here too

int printHello() const { return printf("Hello\n"); }

(and you didn't have a 'return' there)
};

class CGetter
{
public:
CGetter() { test = new CTest; }

Think "initialisation" instead of "assignment".
~CGetter() { delete test; }

And read about the "Rule of Three".
void getTestPtr(const ITest*& t) const;

Why do you think you need the 'const' qualifiers?
private:
CTest * test;
};

void CGetter::getTestPtr(const ITest*& t) const
{
t = test;
return;
}

int main( int argc, char *argv[] )

If you don't use 'argc' and 'argv', there is no sense to have them.
{
ITest * it;
CGetter g;
g.getTestPtr((const ITest*) it);
it->printHello();
return 0;
}

The problem is with the "it" pointer in main.
Debugging the CGetter::getTestPtr() fnc. I can see:
"test" pointer address = (CTest *) 0x8049c20
after a assignment,
"t" pointer address = (const ITest *&) @0xbffff88c: 0x8049c20
and back in main,
"it" pointer address points to: (ITest *) 0x4023f620
causing segmentation fault.
In Win32 this test works... Any Idea?

The problem is in the fact that you probably have the 'test' object
sliced. Drop the 'const's int the getTestPtr and see if it makes
a difference.

V
 
A

Andre Kostur

Hi,
I'm porting a project from Win32 to Linux(debian) and I found a problem
using interfaces.

No such thing as "interfaces" in Standard C++.
For simplify the question, I created a small test and here is the code:
#include <stdio.h>

Should be #include said:
#define interface struct

This is probably not a good idea. If you mean struct, why not just say
struct?
interface ITest
{
virtual int printHello() = 0;
protected:
virtual ~ITest(){};
};

class CTest : public ITest
{
public:
CTest(){ }
virtual ~CTest() { }
private:
//ITest Interface
int printHello() { printf("Hello\n"); }
};

class CGetter
{
public:
CGetter() { test = new CTest; }
~CGetter() { delete test; }
void getTestPtr(const ITest*& t) const;
private:
CTest * test;
};

void CGetter::getTestPtr(const ITest*& t) const
{
t = test;
return;
}

int main( int argc, char *argv[] )
{
ITest * it;
CGetter g;
g.getTestPtr((const ITest*) it);
it->printHello();
return 0;
}

The problem is with the "it" pointer in main.
Debugging the CGetter::getTestPtr() fnc. I can see:
"test" pointer address = (CTest *) 0x8049c20
after a assignment,
"t" pointer address = (const ITest *&) @0xbffff88c: 0x8049c20
and back in main,
"it" pointer address points to: (ITest *) 0x4023f620
causing segmentation fault.
In Win32 this test works... Any Idea?

I'm not sure how I can explain it, but you're doing some really funky
things with const and non-const stuff. And I'm thinking that the
compiler may be making a temporary for that casting of "it".

BTW: _Why_ do you want to cast "it"? Why not declare it as a const
pointer to begin with?
 
A

Andre Kostur

I'm not sure how I can explain it, but you're doing some really funky
things with const and non-const stuff. And I'm thinking that the
compiler may be making a temporary for that casting of "it".

BTW: _Why_ do you want to cast "it"? Why not declare it as a const
pointer to begin with?

Umm... I meant a pointer to const ITest... not a const pointer....
 
D

Dietmar Kuehl

Andre said:
Should be #include <cstdio>

I disagree! There are many errors in the code but this is *not* one
of them. The problem is that the real life has proven the approach
of defining C library names in namespace std to hard to implement.
Essentially, you'd need control over the C library: the standard C
library headers typically contain more than just the standard C
declarations. This causes problems without end. As a consequence,
most standard C++ libraries declare standard C names in the global
namespace and import them into namespace std. This practise may
masquarade errors surfacing with conforming implementations. The
same problem does not occur with the ".h" version, effectively
making them a better choice.
 

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

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,738
Latest member
JinaMacvit

Latest Threads

Top