I was trying to create two classes, the first with a non-const implementation of the functions, the second with a const implementation. Here is a small example:
class Base {
protected:
int some;
};
class A : public virtual Base {
const int& get() const {
return some;
}
};
class B : public virtual Base {
int& get() {
return some;
}
};
class C : public A, B {};
C test;
test.get(); // ambiguous
The call to the get function is ambiguous. No matter that the const version needs to match more requirements. (Calling get on const C is ambiguous as well, but there is one possible function to call.)
Is there a reason for such behaviour in the standard? Thanks!
Ambiguity occurs when compiler tries to figure out to what entity does the name get refer to, prior to overload resolution. It can be a name of function from class A or from class B. In order to build a list of overloads complier needs to select just one of the classes to pull functions from. In order to fix it you can bring that name from both of the base classes into derived class (and make them public):
class C : public A, public B { public: using A::get; public: using B::get; };
The problem is that you don't actually have one unified overload-set, in which the mutable variant would be unambiguously best, but two distinct overload-sets, in A and B, and the compiler will not automatically merge them.
Put
using A::get;
using B::get;
in C to merge the overload-sets and thus resolve the ambiguity.
Related
I have several classes D with public sections of the form:
class D
{
public:
D& foo();
void bar(D&);
}
I'd like to create a single abstract class from which they all derive.
My (naive) attempt was:
// in .h file
class B
{
public:
virtual B& foo() = 0;
virtual void bar(B&) = 0;
}
class D : public B
{
public:
D& foo() override;
void bar(D&) override;
}
// in .cpp file
D& D::bar() {return *(new D());}
void D::foo(D& d) {}
This failed to compile for (what I eventually realized was) a fairly sensible reason: Any function overriding the function
void bar(B&)=0;
must be defined for any parameter which is a reference to type B. The supplied candidate
virtual void bar(D&) override;
is only defined for (the smaller collection) of parameters which are references to type D.
Note that this is not a problem with the function foo. Indeed, if you comment out the three lines with bar, everything compiles fine.
I think that the technical explanation for this phenomenon is that C++ does not support covariance in parameters (but it does support contravariance in parameters).
The answer to the post C++ covariance in parameters suggests that I can't define an interface (i.e. an abstract class) for my classes D.
Is there some simple or conventional way to create a single "interface" for all my classes D? Alternatively, perhaps there is a different design pattern for hiding the different implementations of these classes.
Thanks in advance for your comments and suggestions.
dan
You can't, and for good reason. A derived class can't add preconditions that are more restrictive than the interface it derives from without breaking every principle of OOP that exists. By requiring the parameter to be more specific in your implementation of the interface this is exactly what you are doing.
An argument could be made that something like this could be useful:
struct IfaceA {};
struct IfaceB : IfaceA {};
struct Base { void f(IfaceB &); };
struct Derived : Base { void f(IfaceA &); };
This lessens preconditions rather than increase them, so it's OK. It's simply not done in C++, or any other language I'm aware of for that matter, so you just can't do it.
In both cases you can make an overload with the alternative parameter type and call the overridden version.
It's the opposite case with return types. Return values are post-conditions. You can make post conditions more specific, but can't make them more broad. So you can return your derived type but can't broaden it by returning a more abstract type. C++ implements covariant returns though at least one, very commonly used compiler does it very badly so that there are numerous bugs.
Based on the code that you have provided you have tried to override two diferent function signatures.
The best option you have is use the same signature, and then cast the result.
A simple example,
// in .h file
class B
{
public:
virtual B* foo() = 0;
virtual void bar(B*) = 0;
};
class D : public B
{
public:
B* foo() override;
void bar(B*) override;
};
// in .cpp file
B* D::foo()
{
D* p=new D();
return p;
}
void D::bar(B* d)
{
D* casted=dynamic_cast<D*>(d);
}
int main(void)
{
D son;
B* father=dynamic_cast<B*>(son.foo());
}
I hope that this can solve your problem, or at least give you a clue.
Could you use a templated base class?
template <typename Deriving>
struct Base {
virtual Deriving& foo() = 0;
virtual void bar(Deriving&) = 0;
};
struct Deriving : public Base<Deriving> {
...
};
You don't have a single interface class, but there is a single interface template, which is sometimes versatile enough.
Suppose there is this interface:
class A{
public:
virtual foo()=0;
};
And a class B which implements this interface:
class B:public A{
public:
virtual foo(){} //Foo implemented by B
}
Finally, a class C which has classes A and B as base classes:
Class C : public A, public B {
};
My question is, there is a way to tell the compiler that the implementation for foo is the one from class B without doing an explicit call to B::foo()?
As #BenVoigt pointed out in the comments, the below answer only works due to a bug in g++ (meaning it isn't guaranteed to keep working, and it definitely isn't portable). Thus, although it may do what you want if you use a particular (buggy) compiler, it isn't an option you should use.
Do use virtual inheritance though.
This isn't exactly the scenario that the code in the question implies, but the sentence
My question is, there is a way to tell the compiler that the
implementation for foo is the one from class B without doing an
explicit call to B::foo()?
seems to be asking for syntax to distinguish between multiple base versions of a function without using the :: qualifier.
You can do this with the using directive:
#include <iostream>
class A {
public:
A(){}
virtual void foo(){std::cout<<"A func";}
};
class B: virtual public A {
public:
B(){}
virtual void foo(){std::cout<<"B func";}
};
class C:virtual public A, virtual public B {
public:
C(){}
using A::foo; // tells the compiler which version to use
// could also say using B::foo, though this is unnecessary
};
int main() {
C c;
c.foo(); // prints "A func"
return 0;
}
Of course, the code itself in the question doesn't require this at all, as the other answers have pointed out.
Just use virtual inheritance, so that the A subobject provided by B is the same object used in C.
Or write class C : public B... it will be implicitly usable as an A anyway, via the base class B.
Before the question was edited:
B::foo is not compatible with A::foo.
The required signature is
ReturnType /* missing from question */ foo(A* const this /* this parameter is implicit */);
But B::foo has the signature
ReturnType foo(B* const this);
An A*, which will be passed to the virtual function, is not a B*, which the implementation requires. If B inherited from A, then the compiler would generate B::foo to accept an A* const subobject and find the B* const this object from that subobject pointer. But B::foo has no knowledge of the relationship in C.
As you have the two base classes in your example (which might be a design issue/design smell, I'd review that) you have to explicitly call the implementation that you are after, be it A::foo() or B:foo().
If all B does is to provide the implementation of foo() I'd consider moving the implementation into A (you can provide an implementation for a pure virtual function) but even in this case you'd have to call it via its qualified name.
class A {
public:
void fa() {
}
};
class B : public A{
public:
void fb() {
}
};
class C : public A, public B {
public:
void fc() {
//call A::fa(), not B::A::fa();
}
};
How to call A::fa() from C::fc() function.
GCC warns withdirect base A inaccessible in C due to ambiguity, does this mean there is no direct way to refer base class members?
One option would be to create a stub class that you can use for casting to the right base class subobject:
struct A {
void fa() { }
};
struct B : A {
void fb() { }
};
// Use a stub class that we can cast through:
struct A_ : A { };
struct C : A_, B {
void fc() {
implicit_cast<A_&>(*this).fa();
}
};
Where implicit_cast is defined as:
template <typename T> struct identity { typedef T type; }
template <typename T>
T implicit_cast(typename identity<T>::type& x) { return x; }
I just found the following info from ISO C++ 2003 standard (10.1.3)
A class shall not be specified as a direct base class of a derived class more than once. [Note: a class can be
an indirect base class more than once and can be a direct and an indirect base class. There are limited
things that can be done with such a class. The non-static data members and member functions of the direct
base class cannot be referred to in the scope of the derived class. However, the static members, enumerations
and types can be unambiguously referred to.
It means there is no direct way :(
I just compiled you code on codepad.org , putting A::fa() is enough to call fa() from your C::fc() function.
void fc() {
A::fa();
}
The below is the link to codepad with your code.
http://codepad.org/NMFTFRnt
I don't think you can do what you want. There is an ambiguity here: when you say A::fa(), it still doesn't tell the compiler which A object to use. There isn't any way to access class A. That's what the warning is telling you.
This seems like an awfully strange construct, though. Public inheritance should be used for is-a relationships. You are saying that C is-a A twice over? It doesn't make sense. And that suggests that this is either an artificial example that would never come up in practice, or you should reconsider this design.
You can use virtual inheritance to overcome such problem:
class B : virtual public A {
Now, you can use A::fa() simply in the child class C.
void fc()
{
fa();
}
However, I generally don't see any practical need to inherit class A again into class C, when B is already publically inheriting A. So, In your case, you can make it simple:
class C : public B {
Edit:
If you want 2 instances for A. then the direct instance which you are intending can be made as an object of C:
class C : public B {
A obj;
Because, having a directly inherited A will not be usable in anyway. You cannot declare any pointer or reference to it inside the scope of C.
assume the following class is given:
class Base{
public:
Base() {}
Base( const Base& b) : base_attr(b.base_attr) {}
void someBaseFunction()
{ .... }
protected:
SomeType base_attr;
};
When I want a class to inherit from this one and include a new attribute for the derived class, I would write:
class Derived: public Base {
public:
Derived() {}
Derived( const Derived& d ) : derived_attr(d.derived_attr)
{
this->base_attr = d.base_attr;
}
void SomeDerivedFunction()
{ .... }
private:
SomeOtherType derived_attr;
};
This works for me (let's ignore eventually missing semicolons or such please).
However, when I remove the "this->" in the copy constructor of the derived class, the compiler complains that "'base_attr' was not declared in this scope".
I thought that, when inheriting from a class, the protected attributes would then also be accessible directly. I did not know that the "this->" pointer was needed.
I am now confused if it is actually correct what I am doing there, especially the copy-constructor of the Derived-class.
Because each Derived object is supposed to have a base_attr and a derived_attr and they obviously need to be initialized/set correctly.
And because Derived is inheriting from Base, I don't want to explicitly include an attribute named "base_attr" in the Derived-class. IMHO doing so would generally destroy the idea behind inheritance, as everything would have to be defined again.
EDIT
Thank you all for the quick answers. I completely forgot the fact that the classes actually are templates.
Please, see the new examples below, which are actually compiling when including "this->" and are failing when omiting "this->" in the copy-constructor of the Derived-class:
Base-class:
#include <iostream>
template<class T>
class Base{
public:
Base() : base_attr(0) {}
Base( const Base& b) : base_attr(b.base_attr) {}
void baseIncrement()
{ ++base_attr; }
void printAttr()
{
std::cout << "Base Attribute: " << base_attr << std::endl;
}
protected:
T base_attr;
};
Derived-class:
#include "base.hpp"
template< class T >
class Derived: public Base<T>{
public:
Derived() : derived_attr(1) {}
Derived( const Derived& d) : derived_attr(d.derived_attr) {
this->base_attr = d.base_attr;
}
void derivedIncrement()
{ ++derived_attr; }
protected:
T derived_attr;
};
and for completeness also the main function:
#include "derived.hpp"
int main()
{
Derived<int> d;
d.printAttr();
d.baseIncrement();
d.printAttr();
Derived<int> d2(d);
d2.printAttr();
return 0;
};
I am using g++-4.3.4.
Although I understood now that it seems to come from the fact that I use template-class definitions, I did not quite understand what is causing the problem when using templates and why it works when not using templates. Could someone please further clarify this?
You are only seeing this if Base in some way depends on template arguments.
In that case, it's deemed too dangerous that a name like base_attr is lookup up in such a dependent base class: For some template instantiation, the name could be found in the base class, and for another instantiation, the member could be absent and the name would refer to a some namespace member.
Because this was thought to be confusing, C++ follows the consistent rule that base_attr is never lookup in a dependent base class when doing unqualified name lookup. You need to prefix the name with this-> or with the name of the class as in Derived<T>::base_attr. So when the base class doesn't declare a base_attr, the name doesn't silently refer to a potentially globally declared name, but it will just be a compile time error.
There is no reason that this should be necessary. All member variables are implicitly accessed through this-> and I know of no language rules that specify that you should need to use this-> to access any member functions or variables.
I don't know why you're getting that error without seeing a compilable example, but you can write your copy constructor thus:
Derived( const Derived& d ) : Base(d.base_attr), derived_attr(d.derived_attr) {}
What compiler are you using? I'm not getting any error with g++ and nor do I see anything wrong with the code you have listed.
This question already has answers here:
Function with same name but different signature in derived class not found
(2 answers)
Closed 8 years ago.
Given the following example, why do I have to explicitly use the statement b->A::DoSomething() rather than just b->DoSomething()?
Shouldn't the compiler's overload resolution figure out which method I'm talking about?
I'm using Microsoft VS 2005. (Note: using virtual doesn't help in this case.)
class A
{
public:
int DoSomething() {return 0;};
};
class B : public A
{
public:
int DoSomething(int x) {return 1;};
};
int main()
{
B* b = new B();
b->A::DoSomething(); //Why this?
//b->DoSomething(); //Why not this? (Gives compiler error.)
delete b;
return 0;
}
The two “overloads” aren't in the same scope. By default, the compiler only considers the smallest possible name scope until it finds a name match. Argument matching is done afterwards. In your case this means that the compiler sees B::DoSomething. It then tries to match the argument list, which fails.
One solution would be to pull down the overload from A into B's scope:
class B : public A {
public:
using A::DoSomething;
// …
}
Overload resolution is one of the ugliest parts of C++
Basically the compiler finds a name match "DoSomething(int)" in the scope of B, sees the parameters don't match, and stops with an error.
It can be overcome by using the A::DoSomething in class B
class A
{
public:
int DoSomething() {return 0;}
};
class B : public A
{
public:
using A::DoSomething;
int DoSomething(int x) {return 1;}
};
int main(int argc, char** argv)
{
B* b = new B();
// b->A::DoSomething(); // still works, but...
b->DoSomething(); // works now too
delete b;
return 0;
}
No, this behaviour is present to ensure that you don't get caught out inheriting from distant base classes by mistake.
To get around it, you need to tell the compiler which method you want to call by placing a using A::DoSomething in the B class.
See this article for a quick and easy overview of this behaviour.
The presence of a method in a derived class hides all methods with the same name (regardless of parameters) in base classes. This is done to avoid problems like this:
class A {} ;
class B :public A
{
void DoSomething(long) {...}
}
B b;
b.DoSomething(1); // calls B::DoSomething((long)1));
than later someone changes class A:
class A
{
void DoSomething(int ) {...}
}
now suddenly:
B b;
b.DoSomething(1); // calls A::DoSomething(1);
In other words, if it didn't work like this, a unrelated change in a class you don't control (A), could silently affect how your code works.
This has something to do with the way name resolution works. Basically, we first find the scope from which the name comes, and then we collect all overloads for that name in that scope. However, the scope in your case is class B, and in class B, B::DoSomething hides A::DOSomething:
3.3.7 Name hiding [basic.scope.hiding]
...[snip]...
3 In a member function definition, the declaration of a local name hides
the declaration of a member of the class with the same name; see
basic.scope.class. The declaration of a member in a derived class
(class.derived) hides the declaration of a member of a base class of
the same name; see class.member.lookup.
Because of name hiding, A::DoSomething is not even considered for overload resolution
When you define a function in a derived class then it hides all the functions with that name in the base class. If the base class function is virtual and has a compatible signature then the derived class function also overrides the base class function. However, that doesn't affect the visibility.
You can make the base class function visible with a using declaration:
class B : public A
{
public:
int DoSomething(int x) {return 1;};
using A::DoSomething;
};
That's not overloading! That's HIDING!
When searching up the inheritance tree for the function to use, C++ uses the name without arguments, once it has found any definition it stops, then examines the arguments. In the example given, it stops in class B. In order to be able to do what you are after, class B should be defined like this:
class B : public A
{
public:
using A::DoSomething;
int DoSomething(int x) {return 1;};
};
The function is hidden by the function with the same name in the subclass (but with a different signature). You can unhide it by using the using statement, as in using A::DoSomething();