I have the following problem. A class E overrides two methods: one comes from an abstract class D which inherits from a specialization of a templated class C<T> where T = A. The other is from C<A> directly. And both have the same name.
Now, D should have access to both methods: doSomething(const A& a) because it inherits it from C, and doSomething(const B& b) because D declares it.
However, the following code does not compile, because the compiler recognizes only the method doSomething(const B&) from the pointer to D
#include <iostream>
#include <sstream>
using namespace std;
class A {
private:
int a = 10;
public:
inline std::string hello() const{
std::stringstream ss;
ss << a;
return ss.str();
}
};
class B {
private:
int b = 20;
public:
inline std::string hello() const{
std::stringstream ss;
ss << b;
return ss.str();
}
};
template <class T>
class C {
public:
inline virtual bool doSomething(const T& t) {
std::cout << "C is doing something with T" << t.hello() << std::endl;
return true;
}
};
class D : public C<A> {
public:
virtual void doSomething(const B& b) = 0;
};
class E : public D {
public:
inline bool doSomething(const A& a) override {
std::cout << "E is doing something with A: " << a.hello() << std::endl;
return true;
}
inline void doSomething(const B& b) override {
std::cout << "E is doing somethign with B: " << b.hello() << std::endl;
}
};
int main()
{
A a;
B b;
D* d = new E();
d->doSomething(b);
d->doSomething(a); // compile error, does not recognize doSomething(const A&)
delete d;
}
The compiler shows the following error:
In function ‘int main()’:
main.cpp:62:19: error: no matching function for call to ‘D::doSomething(A&)’
d->doSomething(a); // compile error, does not recognize doSomething(const A&)
^
main.cpp:39:18: note: candidate: virtual void D::doSomething(const B&)
virtual void doSomething(const B& b) = 0;
^
main.cpp:39:18: note: no known conversion for argument 1 from ‘A’ to ‘const B&’
Why is that?
This happens because compiler does not automatically merge all the functions from the base classes to the set of overloaded functions to select from. That is the set of overloaded functions considered when you call d->doSomething(a); consists only of D::doSomething(const B& b). In order to fix this you need to bring C<A>::doSomething; into D class
class D : public C<A> {
public:
using C<A>::doSomething;
virtual void doSomething(const B& b) = 0;
};
To make a base class function visible in the derived class which is hidden by a function of the same name, you should use the using directive (using C<A>::doSomething;).
However, I also want to add that GCC 8.2 reports that there is undefined behavior in the code when you delete d. This is because the class D has a non-virtual destructor.
warning: deleting object of abstract class type 'D' which has non-virtual destructor will cause undefined behavior [-Wdelete-non-virtual-dtor]
delete d;
See demo here.
Related
Say i have this part of code:
#include<iostream>
using namespace std;
class A {
public:
virtual int f(const A& other) const { return 1; }
};
class B : public A {
public:
int f(const A& other) const { return 2; }
virtual int f(const B& other) const { return 3; }
};
void go(const A& a, const A& a1, const B& b) {
cout << a1.f(a) << endl; //Prints 2
cout << a1.f(a1) << endl; //Prints 2
cout << a1.f(b) << endl; //Prints 2
}
int main() {
go(A(), B(), B());
system("pause");
return 0;
}
I can understand why the first two will print 2. But I cannot understand why the last print is also 2. Why doesn't it prefers the overloaded function in B?
I already looked at this and this but I couldn't manage to understand from these.
int B::f(const B& other) const doesn't override int A::f(const A& other) const because the parameter type is not the same. Then it won't be called via calling f() on reference of the base class A.
If some member function vf is declared as virtual in a
class Base, and some class Derived, which is derived, directly or
indirectly, from Base, has a declaration for member function with the
same
name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers
Then this function in the class Derived is also virtual (whether or
not the keyword virtual is used in its declaration) and overrides
Base::vf (whether or not the word override is used in its
declaration).
If you use override specifier (since C++11) compiler will generate the error.
class B : public A {
public:
int f(const A& other) const { return 2; }
virtual int f(const B& other) const override { return 3; }
};
Such as Clang:
source_file.cpp:10:17: error: 'f' marked 'override' but does not override any member functions
virtual int f(const B& other) const override { return 3; }
^
If you add an overload for it in the base class, you might get what you want. Note that a forward declaration of class B will be needed.
class B;
class A {
public:
virtual int f(const A& other) const { return 1; }
virtual int f(const B& other) const { return 1; }
};
LIVE
It's easy, really. You're calling f on an object with static type A. A has only one f, so there's only one entry in the vtable for that function. Overload resolution takes place compile-time. The overload will only be resolved if you call it on an object whose static type is B
The confusion comes in that your:
int f(const A& other) const { return 2; }
line is actually virtual also and is overriding your line:
virtual int f(const A& other) const { return 1; }
Meanwhile, the line:
virtual int f(const B& other) const { return 3; }
ends up being completely ignored because everything matches to the "return 1" line, then follows polymorphically up the chain to the "return 2" line. As the other poster said, the const B portion means it won't match the polymorphic method call.
As an aside: If you're getting a 2 on the first line, I'm suspicious of undesired stack behavior. I'd expect a 1. Perhaps try allocating like this:
A a1;
B b1, b2;
go(a1, b1, b2);
My question is why I cannot call protected virtual member function in derived class through a pointer to the base class unless declaring derived class as a friend of base class?
For example:
#include <iostream>
class A {
friend class C; // (1)
protected:
virtual void foo() const = 0;
};
class B : public A {
void foo() const override { std::cout << "B::foo" << std::endl; }
};
class C : public A {
friend void bar(const C &);
public:
C(A *aa) : a(aa) { }
private:
void foo() const override {
a->foo(); // (2) Compile Error if we comment out (1)
//this->foo(); // (3) Compile OK, but this is not virtual call, and will cause infinite recursion
std::cout << "C::foo" << std::endl;
}
A *a;
};
void bar(const C &c) {
c.foo();
}
int main() {
B b;
C c(&b);
bar(c);
return 0;
}
The output is
B::foo
C::foo
In the above code, I want to call virtual function foo() through member a of class C (not the static bound one through this at compile time), but if I don't make C as A's friend, the call is illegal.
I think C is inherited from A, so that it can access the protected member of A, but why is it actually not happen?
Class C can access the protected members of its own base class, but not members of any other A.
In your example, the parameter a is part of the totally unrelated class B to which C has no access rights (unless you make it a friend).
I have stumbled on a problem while trying to re-use code from different classes. I post it here in hope that some of you might be able to help me.
I have a set of classes (B,C) deriving from the same class (A) which forces the implementation of some methods (foo, run). Class B implements these method, and both B and C provide other methods:
#include<iostream>
template<class I, class O>
class A {
public:
A() {}
virtual ~A() {}
virtual void foo() const = 0; // force implementation of this function
virtual void run() const = 0; // force implementation of this function
};
template<class I, class O>
class B : public A<I,O> {
public:
B() {}
virtual ~B() {}
virtual void foo() const { // implementation for the Base class
std::cout << "B's implementation of foo" << std::endl;
}
virtual void run() const { // implementation for the Base class
std::cout << "B's implementation of run" << std::endl;
}
virtual void foobar() const { // some other function provided by this class
std::cout << "B's implementation of foobar" << std::endl;
}
};
template<class I, class O, class M>
class C : public A<I,O> {
public:
C() {}
virtual ~C() {}
virtual void bar(M m) const { // some other function provided by this class
std::cout << "C's implementation of bar with: " << m << std::endl;
}
};
Now, what I am trying to do is inherit from both B and C so that I can have the extra methods (foobar, bar), but also not have to implement the method from class A (foo) because it is already defined in B:
template<class I, class O>
class D : public B<I,O>, public C<I,O,int> {
public:
D() {}
void run() const {
this->bar(123);
this->foo();
this->foobar();
}
};
But for some reason the compiler gives me this error:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:68:35: error: cannot allocate an object of abstract type ‘D<float, double>’
A<float, double> *d = new D<float, double>(); // what I need to do
test.cpp:48:11: note: because the following virtual functions are pure within ‘D<float, double>’:
class D : public B<I,O>, public C<I,O,int> {
^
test.cpp:9:22: note: void A<I, O>::foo() const [with I = float; O = double]
virtual void foo() const = 0; // force implementation of this function
This is the code I use to run it:
int main(int argc, char **argv)
{
A<float, double> *b = new B<float, double>();
b->foo(); // prints "B's implementation of foo"
b->run(); // prints "B's implementation of run"
//A<float, double> *c = new C<float, double, int>(); // obviously fails because C does not implement any of A's functions
//A<float, double> *d = new D<float, double>; // line 68: what I need to do
//d->run(); // ***throws the abstract class error
return 0;
}
I want to use the 'run' function of an object of class D from a pointer to a A. As all the functions are virtual I expect to execute implementation of each function defined in the lowest inheritance point, meaning that 'B::run' will be discarded. As 'D::run' uses functions from both B and C I need to inherit from both classes.
I hope I have described it enough and not confused anybody.
Thanks for the help!
If you change B and C to virtually inherit from the A template class, they will share a single base instance when combined by D and this error will go away:
template<class I, class O>
class B : virtual public A<I,O> {
// ...
template<class I, class O, class M>
class C : virtual public A<I,O> {
However, this pattern (known as the diamond inheritance (anti-)pattern) can be very difficult to reason about and I would strongly suggest avoiding it if possible. You are likely to run into even more obscure problems later.
Here is a sample of this technique working, but showing some results that may not be expected at first glance:
class A {
public:
virtual void foo() = 0;
};
class B : virtual public A {
public:
virtual void foo() override;
};
void B::foo()
{
std::cout << "B::foo()" << std::endl;
}
class C : virtual public A { };
class D : public B, public C { };
int main() {
D d;
C & c = d;
c.foo();
return 0;
}
Note that even though you are calling C::foo(), which is pure virtual, since there is only one A instance the inherited pure virtual function resolves to B::foo() though the shared A vtable. This is a somewhat surprising side-effect -- that you can wind up invoking methods implemented on a cousin type.
The answer by #cdhowie gives you a solution.
To understand the problem the compiler is complaining about, take a set of simpler classes:
struct A
{
virtual void foo() = 0;
};
struct B : A
{
virtual void foo() {}
}
struct C : A
{
void bar() {}
}
struct D : B, C
{
};
The class hierarchy of D is:
A A
| |
B C
\ /
D
With this inheritance structure, D has two virtual tables, one corresponding to the B inheritance hierarchy and one corresponding to C inheritance hierarchy. The difference being that in the B hierarchy, there is an implementation of A::foo() while there isn't one in the C hierarchy.
Let's say you were allowed to construct an object of type D.
D d;
C* cp = &d;
Now cp points to the C hierarchy of D, and uses a virtual table in which foo is not implemented. That will be a run time error that the compiler is helping you avoid at compile time.
I know this is a late answer but since you are deriving from a pure virtual function for class C, you have to implement it, then in those functions you call the base class:
virtual void foo() const { // for class C
B::foo();
}
In the following code
#include <iostream>
using namespace std;
class A {
public:
A() {}
virtual ~A() {};
};
class B : public A {
public:
B() {}
virtual ~B() {};
};
void process(const A&) {
cout << "processing A" << endl;
}
void process(const B&) {
cout << "processing B" << endl;
}
int main(void) {
A* a = new B;
process(*a);
return 0;
}
the output of running it becomes
processing A
but I would have assumed that it should have been
processing B
since a points to the derived class B and not A. So why does it call the first implementation of process function and not the second?
The static type of expression *a is A because a was declared as
A* a = new B;
The compiler resolves the selection of overloaded functions using the static type of the argument.
Even when virtual functions are called the compiler uses the static type of the object to call appropriate function. The difference is only that the compiler uses the table of pointers to virtual functions to indirectly call the required function.
You need to make process() a virtual member function of A, B:
class A {
public:
A() {}
virtual ~A() {};
virtual void process() const { cout << "processing A" << endl; }
};
class B : public A {
public:
B() {}
virtual ~B() {};
virtual void process() const override { cout << "processing B" << endl; }
};
int main(void) {
A* a = new B;
a->process();
return 0;
}
In your current code, *a is of type A&, so the closest match to process(*a); is the first overload (for const A&).
void process(const A&); is a better (exact) match, since dereferencing A* gives you A&.
Short answer, but there isn't much more to say unless you want a reference from the standard.
You could dynamic_cast the result of *a and that would give you a B&, but that's smelly desing. What you probably want is a virtual function in A that's overriden in B (assume it's called foo). Then, calling a->foo() would dispatch to B::foo.
I wrote code when one class has only constant access to its content, and that was inherited by other class which provides the same method, but with normal access to its members. When I try to compile it by gcc I get following error code:
error: passing ‘const A’ as ‘this’ argument of ‘void A::operator()()’ discards qualifiers
here is sample compilable code:
#include<stdio.h>
class ConstA {
public:
void operator()() const {
printf("const\n");
}
};
class A : public ConstA {
public:
void operator()() {
printf("non-const\n");
}
};
class B : public A {
};
void f(const A& a) {
a();
}
int main() {
B b;
f(b);
}
Compiler tries to invoke method(operator ()) without const attribute, while const method is accessible in base ConstA class. I do not know why I get this kind of error.
The const method is not accessible, the base class version is hidden by the derived class version, an annoying problem. You need using ConstA::operator() to bring it into the scope of A.
class A : public ConstA{
public:
using ConstA::operator();
void operator()(){
printf("non-const\n");
}
};
For further reading, look at this question of mine, which has some good explanations.
it is because C++ uses hiding on overloading, so after overloading, ConstA::operator() is NOT accessable
consider the following program:
class A {
public:
void foo() { cout << "A" << endl; }
};
class B : public A {
public:
void foo(int x) { cout << "B" << endl; }
};
int main() {
B b;
b.foo();
}
this one will also generate a compile error, because B::foo() is hidden! to envoke it you'll have to explicitly cast to A.
so in your example, you'll have to explicitly cast to ConstA