From: jbuck@forney.berkeley.edu (Joe Buck)
Newsgroups: gnu.g++.help
Subject: Re: what is a "contravarience violation for method types"
Date: 23 Nov 1992 20:06:42 GMT
Organization: U. C. Berkeley
Distribution: world
NNTP-Posting-Host: forney.berkeley.edu

In article <SETHG.92Nov23113233@roar.CS.Berkeley.EDU> sethg@roar.CS.Berkeley.EDU (Seth C. Goldstein) writes:
>When compiling the following with g++-2.3.1 I get warnings of the form:
>
>quad.C: In method `Toplevel::Toplevel ()':
>quad.C:27: warning: contravariance violation for method types ignored
>
>What does it mean?
>
>example:
>////////////////////////////////////////////////////////////////////////
>class Frame;
>typedef void (Frame::*Codeblock)(void);
>
>class Frame
>{
>protected:
>    int         counter;
>
>public:
>    inline      Frame(Codeblock function);
>};
>
>class Toplevel : Frame
>{
>    int         i;
>public:
>                Toplevel(void);
>    void        runtop(void);
>};
>
>Toplevel::Toplevel(void) : Frame(&(Toplevel::runtop))	// line 27
>{
>
>}

This is a horribly phrased error message, but I don't know of a short
way to describe the problem.  You are using a pointer to a Toplevel
member function where a pointer to a Frame function is desired.  This
is a no-no.  Here's why: assume the code were written this way:

typedef void (Frame::*Codeblock)(void);

class Frame {
	Codeblock funcP;
public:
	Frame(Codeblock function);
	void doItTo(Frame&);
};

class Toplevel : Frame
{
    int         i;
public:
                Toplevel(void);
    void        runtop(void);
};

Toplevel::Toplevel(void) : Frame(&(Toplevel::runtop)) {}

void Toplevel::runTop() { i = 1;}

// Now here's where the problem comes from:

void Frame::doItTo(Frame& arg) {
	arg.funcP();
}

Note that arg can be any Frame object, not necessarily a TopLevel.
Now consider the following code:

	TopLevel foo;
	Frame bar;
	foo.doItTo(bar);

We will now attempt to set bar's "i" member to 1 -- but bar has no
i member because it is not a TopLevel.  Result: a crash, or who knows
what.

Pointers to member functions "inherit backwards", hence the word
"contravariant" among the compiler folks.  Given

class Base...

class Derived: public Base...

typedef void (Base::*VoidBaseFuncP)(void);
typedef void (Derived::*VoidDerivedFuncP)(void);

then it is legal to assign a VoidBaseFuncP to a VoidDerivedFuncP without
a cast, but not vice versa.  This is exactly the reverse of the behavior
for pointers to objects, where it is legal to assign a Derived* pointer
to a Base* pointer without a cast, but not vice versa.

Now in your case, you may be able to assure that the TopLevel function
will never be called on a non-TopLevel object through the pointer (perhaps
because functions like doItTo are not present and the function is only
applied to the object itself).  In that case, use a cast to make the
warning disappear, but remember that casts tell the compiler "Don't bother
me, I know what I am doing", so make sure you are!

I would ask the g++ maintainers to consider rephrasing the error message
to something like

warning: unsafe to assign pointer to member of derived class (class YYY)
to pointer to member of base (class XXX)

though I am not sure that this phrasing covers all the situations in which
the present message can be issued.
--
Joe Buck	jbuck@ohm.berkeley.edu
Newsgroups: gnu.g++.help