private inheritance and ambiguous base

N

nguillot

Hello.

Here an example of is-implemented-in-term-of (or has-a) relation, with
a private inheritance:
(please, this is sample code to illustrate my question, don't suggest
me to use composition, even if you would be right).
every class that wants to log must inherit from the following class:

class Loggable
{
protected:
Loggable(std::string className) : className_(className) {}
void Log(std::string text)
{
// a log function, for instance:
std::cout << className_ << ": " << text << endl;
}
private:
std::string className_;
};

Let's have a class A that wants to log:

class A : private Loggable
{
public:
A() : Loggable("A")
{
Log("blabla");
}
};

So far, so good

Now, let's have a class B that wants to log, and inherits from A:

class B : private Loggable, public A
{
public:
B() : Loggable("B")
{
Log("blbblb");
}
};

It produces a warning:
warning: direct base ‘Loggable’ inaccessible in ‘B’ due to ambiguity

and an error:
error: reference to ‘Log’ is ambiguous
error: candidates are: void Loggable::Log(std::string)
error: void Loggable::Log(std::string)

A solution would to use virtual inheritance from Loggable, but I think
it's not what I want:
Maybe it's ambigous for the compiler which Loggable base to use when
we use Log in B, but it's not: as I use private inheritance, the
A::Log should'nt be available in B...

So... is their another solution than virtual inheritance and
composition?
Another question: I don't understand why virtual inheritance fix the
issue: in memory I still have an instance of loggable for A and
another instance for B.

Thank you for your answers.
 
V

Victor Bazarov

Hello.

Here an example of is-implemented-in-term-of (or has-a) relation, with
a private inheritance:
(please, this is sample code to illustrate my question, don't suggest
me to use composition, even if you would be right).
every class that wants to log must inherit from the following class:

class Loggable
{
protected:
Loggable(std::string className) : className_(className) {}
void Log(std::string text)
{
// a log function, for instance:
std::cout<< className_<< ": "<< text<< endl;
}
private:
std::string className_;
};

Let's have a class A that wants to log:

class A : private Loggable
{
public:
A() : Loggable("A")
{
Log("blabla");
}
};

So far, so good

Now, let's have a class B that wants to log, and inherits from A:

class B : private Loggable, public A
{
public:
B() : Loggable("B")
{
Log("blbblb");
}
};

It produces a warning:
warning: direct base ‘Loggable’ inaccessible in ‘B’ due to ambiguity

and an error:
error: reference to ‘Log’ is ambiguous
error: candidates are: void Loggable::Log(std::string)
error: void Loggable::Log(std::string)

A solution would to use virtual inheritance from Loggable, but I think
it's not what I want:
Maybe it's ambigous for the compiler which Loggable base to use when
we use Log in B, but it's not: as I use private inheritance, the
A::Log should'nt be available in B...

Access rights are not considered when names are resolved. Name
resolution is what causes ambiguity. You can solve name resolution if
you provide a hint to the compiler:

B() : Loggable("B")
{
Loggable::Log("blbblb");
}
So... is their another solution than virtual inheritance and
composition?

I think so. Try qualifying the name Log.
Another question: I don't understand why virtual inheritance fix the
issue: in memory I still have an instance of loggable for A and
another instance for B.

Yes, but they share a single instance of Loggable.

V
 
J

James Kanze

On 2/23/2011 4:49 PM, nguillot wrote:
Access rights are not considered when names are resolved. Name
resolution is what causes ambiguity. You can solve name resolution if
you provide a hint to the compiler:
B() : Loggable("B")
{
Loggable::Log("blbblb");
}

The whole point of the error message is that there is no way to
qualify Loggable in a way which specifies the direct base of B.
Loggable:: specifies the Loggable base of B, direct or indirect,
and is ambiguous. The only way to work around the problem is to
introduce an intermediate class, e.g.:

struct LoggableForB : Loggable
{
LoggableForB() : Loggable("B") {}
};

class B : private LoggableForB, A
{
B()
{
LoggableForB::Log("blbblb");
}
};
 
I

itaj sherman

Hello.

Here an example of is-implemented-in-term-of (or has-a) relation, with
a private inheritance:
(please, this is sample code to illustrate my question, don't suggest
me to use composition, even if you would be right).
every class that wants to log must inherit from the following class:

class Loggable
{
protected:
Loggable(std::string className) : className_(className) {}
void Log(std::string text)
{
// a log function, for instance:
std::cout << className_ << ": " << text << endl;
}
private:
std::string className_;

};

first inherit a TypedLoggable<T> instead directly Loggable:

template< typename T >
class TypedLoggable: public Loggable
{
protected:
TypedLoggable( std::string className )
:
Loggable( className )
{}

TypedLoggable()
:
Loggable( typeid(T).name(); )
{}

public:
};

template< typename T >
void Log2( T const& obj, std::string const& text )
{
class A : private Loggable

class A : private TypedLoggable said:
{
public:
A() : Loggable("A")

: TypedLoggable said:
{
Log("blabla");

TypedLoggable<A>::Log( "dasda" );

or

Log2( *this, "blabla");
}

};

So far, so good

Now, let's have a class B that wants to log, and inherits from A:

class B : private Loggable, public A

private TypedLoggable said:
{
public:
B() : Loggable("B")
{
Log("blbblb");

TypedLoggable<B>::Log( "dasda" );

or

Log2( *this, "blblbf" );

Other members of Loggable might make sense in a hasA relation.
But className_ could be a static member function of TypedLoggable<T>
(that may use a singleton to keep the string per T). Keeping a string
copy in every instance might be very wasteful.

itaj
 
I

itaj sherman

The whole point of the error message is that there is no way to
qualify Loggable in a way which specifies the direct base of B.
Loggable:: specifies the Loggable base of B, direct or indirect,
and is ambiguous.  The only way to work around the problem is to
introduce an intermediate class, e.g.:

Is B::Loggable::Log( "afa" ) stadard?

itaj
 

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,962
Messages
2,570,134
Members
46,692
Latest member
JenniferTi

Latest Threads

Top