Thread overview
3 compile problems.
May 12, 2004
Tom Udale
May 12, 2004
Walter
May 12, 2004
Tom Udale
May 13, 2004
Walter
May 14, 2004
Tom Udale
May 14, 2004
Walter
May 15, 2004
Tom Udale
May 17, 2004
Walter
May 19, 2004
Tom Udale
May 12, 2004

I have a large program that is cross compiled between win32 (using visual studio) and win16 (msvc).  For some time I have been searching for a replacment for msvc due since it has such a crappy c++ implementation.  I got the Digital Mars CD some time ago and have finally managed to get enough time to get it up to the latest patches and fix my code enough for the DM compiler to get down to things that strike me as being compiler bugs.

Currently scver reports 8.40.2n as my compiler version which I take to be the most recent.

At the bottom of this post are the test file and command IDE output.  The most egregious problems are #1 and #3.  #2 is just annoying since I think I am alright and the simple changes to fix it for DM breaks my other compilers.

I am hardly a language lawyer so it could just be me in some cases.

I would like very much to ditch msvc so any help would be much appreciated.

Regards,

Tom Udale



// ==============================
// test.cpp

// Problem 1: Crazy derivation (it looks less crazy in context and in any
event I do not think it is illegal)
class RootA
{
public:
 virtual ~RootA();
};

class RootB
{
public:
 virtual ~RootB();
};

class Merge:public RootB,public RootA
{
public:
 ~Merge();
};

class Base:public Merge
{
};


class DBaseA:public Base
{
};

class DBaseB:public Base
{
};

class Test2:private DBaseA,private DBaseB
{
};





// Problem 2: Const and conversion operators.
// This problem was discovered with TestObj being an enum which is much more
sensible
// than the following example which I chose to show the 'fix' of adding
const to the
// return from the const conversion operator.  However, it is my
understanding
// that return values are not supposed to be part of the overload resolution
mechanism
// and if two overloaded methods differ only by constness, then the nature
of the base
// object makes the determination.  Of course, this might be somewhat
different for
// conversion operators since the return type *is* part signature (uggg).
As I think about
// it, it is not clear if the compiler should accept both the conversions on
line A and
// B (which it does)???


struct TestObj{};

class TestObjWrapper
{
    public:
 operator TestObj*();
 operator TestObj*()const;     // (A) this should work no??
 //operator const TestObj*()const;    // (B) uncomment this one for no error
at C
 TestObj*            get();     // these both work as expected.
 TestObj*            get()const;
};



void fc(const TestObj* constHandle)
{
}



void foo()
{
 TestObjWrapper   b;
 TestObjWrapper&   br=b;
 const TestObjWrapper& cbr=b;

 fc(cbr);         // (C)
 fc(cbr.get());
}


// Problem 3: Private derivation

class PrivDeriv:private RootA
{
    void    foo();
};


void foo_a(RootA&)
{
}

void PrivDeriv::foo()
{
    foo_a(*this);
}
//===============================


and here is the command line spit out by the IDE and the errors:



sc
T:\CODE\test.cpp -ml -C -WA -S -3 -a2 -Nc -c -gf -DSC_WIN16 -D_DEBUG -DSTRIC
T -DSC_APP -DSTRAIGHT_C -It:\code\xplib\50x\include -It:\code\iono_com\50x -
It:\code\iwiz\50x\ionwizrd -odebug\test.obj
Error: T:\CODE\test.cpp(35): '??_7Test2@@6FRootA@@Merge@@@' is already
defined
Error: T:\CODE\test.cpp(79): need explicit cast for function parameter 1 to
get
T:\CODE\test.cpp(79): from: const TestObjWrapper
T:\CODE\test.cpp(79): to  : const TestObj*
Error: T:\CODE\test.cpp(98): member 'RootA' of class 'PrivDeriv' is not
accessible
Lines Processed: 97  Errors: 3  Warnings: 0
Build failed





May 12, 2004
I have to look into 1 and 2, but 3 is definitely a coding error (i.e. not a compiler problem). I think you can fix #2 with a cast, or an #ifdef if you must.

"Tom Udale" <tom@tom.com> wrote in message news:c7s1r4$2lb5$1@digitaldaemon.com...
>
>
> I have a large program that is cross compiled between win32 (using visual studio) and win16 (msvc).  For some time I have been searching for a replacment for msvc due since it has such a crappy c++ implementation.  I got the Digital Mars CD some time ago and have finally managed to get
enough
> time to get it up to the latest patches and fix my code enough for the DM compiler to get down to things that strike me as being compiler bugs.
>
> Currently scver reports 8.40.2n as my compiler version which I take to be the most recent.
>
> At the bottom of this post are the test file and command IDE output.  The most egregious problems are #1 and #3.  #2 is just annoying since I think
I
> am alright and the simple changes to fix it for DM breaks my other compilers.
>
> I am hardly a language lawyer so it could just be me in some cases.
>
> I would like very much to ditch msvc so any help would be much
appreciated.
>
> Regards,
>
> Tom Udale
>
>
>
> // ==============================
> // test.cpp
>
> // Problem 1: Crazy derivation (it looks less crazy in context and in any
> event I do not think it is illegal)
> class RootA
> {
> public:
>  virtual ~RootA();
> };
>
> class RootB
> {
> public:
>  virtual ~RootB();
> };
>
> class Merge:public RootB,public RootA
> {
> public:
>  ~Merge();
> };
>
> class Base:public Merge
> {
> };
>
>
> class DBaseA:public Base
> {
> };
>
> class DBaseB:public Base
> {
> };
>
> class Test2:private DBaseA,private DBaseB
> {
> };
>
>
>
>
>
> // Problem 2: Const and conversion operators.
> // This problem was discovered with TestObj being an enum which is much
more
> sensible
> // than the following example which I chose to show the 'fix' of adding
> const to the
> // return from the const conversion operator.  However, it is my
> understanding
> // that return values are not supposed to be part of the overload
resolution
> mechanism
> // and if two overloaded methods differ only by constness, then the nature
> of the base
> // object makes the determination.  Of course, this might be somewhat
> different for
> // conversion operators since the return type *is* part signature (uggg).
> As I think about
> // it, it is not clear if the compiler should accept both the conversions
on
> line A and
> // B (which it does)???
>
>
> struct TestObj{};
>
> class TestObjWrapper
> {
>     public:
>  operator TestObj*();
>  operator TestObj*()const;     // (A) this should work no??
>  //operator const TestObj*()const;    // (B) uncomment this one for no
error
> at C
>  TestObj*            get();     // these both work as expected.
>  TestObj*            get()const;
> };
>
>
>
> void fc(const TestObj* constHandle)
> {
> }
>
>
>
> void foo()
> {
>  TestObjWrapper   b;
>  TestObjWrapper&   br=b;
>  const TestObjWrapper& cbr=b;
>
>  fc(cbr);         // (C)
>  fc(cbr.get());
> }
>
>
> // Problem 3: Private derivation
>
> class PrivDeriv:private RootA
> {
>     void    foo();
> };
>
>
> void foo_a(RootA&)
> {
> }
>
> void PrivDeriv::foo()
> {
>     foo_a(*this);
> }
> //===============================
>
>
> and here is the command line spit out by the IDE and the errors:
>
>
>
> sc
>
T:\CODE\test.cpp -ml -C -WA -S -3 -a2 -Nc -c -gf -DSC_WIN16 -D_DEBUG -DSTRIC
>
T -DSC_APP -DSTRAIGHT_C -It:\code\xplib\50x\include -It:\code\iono_com\50x -
> It:\code\iwiz\50x\ionwizrd -odebug\test.obj
> Error: T:\CODE\test.cpp(35): '??_7Test2@@6FRootA@@Merge@@@' is already
> defined
> Error: T:\CODE\test.cpp(79): need explicit cast for function parameter 1
to
> get
> T:\CODE\test.cpp(79): from: const TestObjWrapper
> T:\CODE\test.cpp(79): to  : const TestObj*
> Error: T:\CODE\test.cpp(98): member 'RootA' of class 'PrivDeriv' is not
> accessible
> Lines Processed: 97  Errors: 3  Warnings: 0
> Build failed
>
>
>
>
>


May 12, 2004
Walter,


Thanks for looking into things.  One question.

> I have to look into 1 and 2, but 3 is definitely a coding error (i.e. not
a
> compiler problem). I think you can fix #2 with a cast, or an #ifdef if you must.

#3 is the one I was quite positive was OK.  Why can't my derived class have access to its own base from within its own member function?

void foo_a(RootA&)
{
}

class PrivDeriv:private RootA
{
     void    foo();
};

void PrivDeriv::foo()
{
   foo_a(*this);
}

Thanks,

Tom




May 13, 2004
To have access, you need to make the derivation 'protected'. Private base classes are not accessible. I'm not enough of an OOP expert to give a compelling rationale for why C++ is that way, you might ask that over in comp.std.c++.

"Tom Udale" <tom@tom.com> wrote in message news:c7u7mi$539$1@digitaldaemon.com...
> Walter,
>
>
> Thanks for looking into things.  One question.
>
> > I have to look into 1 and 2, but 3 is definitely a coding error (i.e.
not
> a
> > compiler problem). I think you can fix #2 with a cast, or an #ifdef if
you
> > must.
>
> #3 is the one I was quite positive was OK.  Why can't my derived class
have
> access to its own base from within its own member function?
>
> void foo_a(RootA&)
> {
> }
>
> class PrivDeriv:private RootA
> {
>      void    foo();
> };
>
> void PrivDeriv::foo()
> {
>    foo_a(*this);
> }
>
> Thanks,
>
> Tom
>
>
>
>


May 14, 2004
Walter,

> To have access, you need to make the derivation 'protected'. Private base classes are not accessible. I'm not enough of an OOP expert to give a compelling rationale for why C++ is that way, you might ask that over in comp.std.c++.

Right, but that is for further derived class, not for the _declaring_ class. The declaring class always has access to its own data, whether they be base classes or member variables.

For example:

class A
{
    public:
    foo();
};

class B{};

void    afoo(A&    aref)
{
}
void    bfoo(B&    aref)
{
}

class C:private A,protected B
{
    void foo()
   {
       A::foo();    // this has to be accessable, even though A is private,
right? -C is the declaring class
                        // (and it is in DM 8.40)

       A&    aref=*this;    // likewise, this should be accessable, but it
is not.
  }
};

void    cfoo(C&    aref)
{
}
class D:private C
{
 void    foo()
 {
  A&    aref=*this;    // Error! I do not have access to A.  DM correctly
flags this.
  B&    bref=*this;    // ok, B is protected as you describe.
  C&    cref=*this;    // should be ok: C is my base but DM complains.

    // Try the above conversions without the intermediate reference.
  afoo(*this);        // Error! I do not have access to C's private base
  bfoo(*this);        // ok ,I have access to C's protected base
     cfoo(*this);        // should be ok, I have access to my private base -
DM complains.
 };
};

What you are talking about earlier is the access of D to private members in C.  I absolutely agree that D cannot access private members (base or otherwise) of C.  It does have access to C's protected base classes.

However, what I am talking about is D and C's access to their _own_ base classes.  Private/public/protected never affects the delcaring class.  The declaring class always has access to its own members.  Otherwise, they would not be able to access thier own data (which is my problem here).


See also:

"Re: Private inheritance" on comp.lang.c++.moderated (from May of 2000)

or

"Q: is this a good reason to use private inheritance"
comp.lang.c++.moderated (from 1997/02/09)




BTW, this behaviour changed in Digital Mars.  When I originally got the CD (somwhere around 8.28), the program in question compiled fine in this partiular respect - I was only encountering problems #1 and #2.  Now it has piles more errors as a result of #3.  I am pretty sure it was between 38 and 40 but cannot be sure.

For what its worth (and I know correctness is not a democracy :) MVSC, Visual Studio, and Watcom all compile this without complaint.

Best regards,

Tom





May 14, 2004
I believe DMC++'s behavior is correct according to the Standard. Of course, I have been wrong before, but I need a compelling argument based on what the Standard says.

"Tom Udale" <tom@tom.com> wrote in message news:c8175o$1gqa$1@digitaldaemon.com...
> BTW, this behaviour changed in Digital Mars.  When I originally got the CD (somwhere around 8.28), the program in question compiled fine in this partiular respect - I was only encountering problems #1 and #2.  Now it
has
> piles more errors as a result of #3.  I am pretty sure it was between 38
and
> 40 but cannot be sure.

That's because I made a pass through the Standard to compile or issue an error message correctly for every example of correct or illegal code in the Standard with regards to access control.

> For what its worth (and I know correctness is not a democracy :) MVSC, Visual Studio, and Watcom all compile this without complaint.

It's common for compilers to have bugs with things like this, so what another compiler does is not sufficiently compelling. You'll need to put on your Standard Language Lawyer Hat <g>.


May 15, 2004
Walter,

> I believe DMC++'s behavior is correct according to the Standard. Of
course,
> I have been wrong before, but I need a compelling argument based on what
the
> Standard says.
Of course.

> > For what its worth (and I know correctness is not a democracy :) MVSC, Visual Studio, and Watcom all compile this without complaint.
>
> It's common for compilers to have bugs with things like this, so what another compiler does is not sufficiently compelling. You'll need to put
on
> your Standard Language Lawyer Hat <g>.
Ok, you have forced me to finally buy the standard :)

Needless to say, even armed with the standard, my language lawyer hat fits somewhat poorly.

Nevertheless, I believe the relevent section of the standard (I am looking at ISO/IEC 14882:2003) is 11.2.4:

4 A base class is said to be accessible if an invented public member of the
base class is accessible. If a base
class is accessible, one can implicitly convert a pointer to a derived class
to a pointer to that base class
(4.10, 4.11).

.....In particular this next part......

[Note: it follows that members and friends of a class X can implicitly convert an X* to a pointer to a private or protected immediate base class of X. ] ...etc


So by my read of the above, the following code should behave as commented:

class A{};

foo(A&)
{
}

class X:private A
{
    void f() // Member of X
    {
            A*    aptr=this;        // This should work given the above note
(A is an immediate base class of X).
            A&   aref=*this;      // Thus this should work since
            A&   aref1=*aptr;   // clearly this will work.

            foo(*this);                // thefore this should work since
            foo(aref1);               // clearly this will work
    }
};



Does that make sense?

Regards,

Tom


May 17, 2004
I'll check it out. Thanks!


May 19, 2004
> I'll check it out. Thanks!
Ok, great.  Thanks alot.

Tom