I have Question about class overriding in C++ - c++

When I study about override keyword, I found some strange thing like below code.
#include <iostream>
template <class T>
class A
{
public:
virtual void some_function(const T a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
std::cout<<"Base"<<std::endl;
}
};
class Derived : public A<int*>
{
public:
virtual void some_function(const int* a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
std::cout<<"Derived"<<std::endl;
}
};
int main()
{
A<int*>* p = new Derived;
p->some_function(nullptr);
delete p;
}
When I first saw that code, I expected "Derived" to be called.
But above code print result like below.
void A<T>::some_function(T) [with T = int*]
Base
But when I removed const keyword in the some_function that placed in Derived class,
class Derived : public A<int*>
{
public:
virtual void some_function(int* a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
std::cout<<"Derived"<<std::endl;
}
};
It print "Derived".
Can you tell me why this is happening?

The function prototypes are not the same. For T=int* const T a: a is a const pointer to an int, while const int *a is a pointer to an const int. For one the pointer is const, for the other the int is const.
int * const a would be the same as const T a, or you can make T=const int*.
https://godbolt.org/z/WEaEoGh58
Also important to note: When you derive from a class you must declare a virtual destructor.
A hint: when you use the keyword override on the derived function, you will get an error that you are not overriding the function: https://godbolt.org/z/o87GMrhsd

At
const T a
const qualifier is interpreted as top-level cv-qualifier for T, so it is processed
T const a
thus if int* is set to T, parameter type becomes
int* const a
So, your Derived's function signature (it is called second level const qualifier)
const int* a
is different from Base's one. As a result, your Derived virtual function is not called.
In addition, C++ has the rule of "ignore top-level cv-qualifier from function signature". So, your Base's signature
int* const
and if you give the type of
int*
into Derived's signature, these two types signature are interpreted to be equivalent. As a result, your Derived virtual function is called correctly.
The following is a back-ground for your help. The type of
T*
has two component T and pointer and then
T* const
is called top-level cv-qualifier which is applied to *, and then
T const *
is called second level cv-qualifier which is applied to T (equal to const T*). C++ ignore top-level cv-qualifier from signature. On the other hand, second level qualifier is included to signature. Therefore for example,
void f(int*) {}
void f(int* const){}
is failed to compile because of same signature by top-level cv-qualifier ignoring. In contrast,
void f(int*) {}
void f(int const * ){}
is compiled successfully by the difference of second level cv-qualifiers.
This is important to understand the behavior of virtual function calls. The reason is that the signature of derived virtual function and base's one must be identical to call it correctly.

Related

C++ overriding virtual templated method

I am trying to override a virtual function in C++. After I override the function, it does not actually override it and thus makes the class abstract.
The code below will give you a good understanding of the problem.
As you can see below, the code works fine for non-pointer templates like an int but fails with an int pointer.
I thought that maybe since it was a problem with references to pointers, I took out the & in the implementation of Derived2 but that did not fix it.
template<class T>
class Base {
virtual void doSomething(const T& t) = 0;
};
class Derived1: public Base<int>{
void doSomething(const int& t) {
} // works perfectly
};
class Derived2: public Base<int*>{
void doSomething(const int*& t) {
}
// apparently parent class function doSomething is still unimplemented, making Derived2 abstract???
};
int main(){
Derived1 d1;
Derived2 d2; // does not compile, "variable type 'Derived2' is an abstract class"
}
Note that for the parameter type const T&, const is qualified on T itself, then when T is a pointer like int *, the const should be qualified on the pointer itself (i.e. int* const), not the pointee (i.e. const int*).
The correct type should be
void doSomething(int* const & t)
BTW: You can use the keyword override to confirm whether the virtual function is overrided correctly.
BTW2: Change the style for const T& to T const& might make it more clear.
LIVE

Cannot call a method of const reference parameter in C++

class A
{
public:
A(){};
~A(){};
void method(){};
};
void call(const A &a)
{
a.method(); // I cannot call this method here if I use "const" but I can call it if not using "const"
}
int main()
{
A a;
call(a);
return 0;
}
In this case, the error is: "passing const A as this argument of void A::method() discards qualifiers [-fpermissive]|"
In function call, if I use const, I get the error, but if I get rid of it, it works.
Can anyone explain it for me?
You can't call non-const member functions via const references. You can fix this by making the member function const:
void method() const {};
^^^^^
This indicates that calling the member does not mutate the object it is called on*
* Conceptually. In practice it can mutate members marked mutable

C++ same name for non-virtual function in derived class conflicts with `final` specifier

This has the feeling of a complete newbie question, but why does the following code not compile when the final specifier is used for B::operator()?
struct A
{
virtual void operator()() const = 0;
};
// the CRTP-component is not really necessary here
// but it possibly makes more sense in that it could be applied like this in reality
//
template<typename Derived>
struct B : A
{
virtual void operator()() const override final
{
static_cast<Derived const&>(*this).operator()();
}
};
struct C : B<C>
{
void operator()() const
{
//do something
}
};
int main()
{
C()();
}
G++ prints the following error message:
main.cpp:17:14: error: virtual function 'virtual void C::operator()() const'
void operator()() const
^
main.cpp:9:22: error: overriding final function 'void B<Derived>::operator()() const [with Derived = C]'
virtual void operator()() const override final
^
I would have thought it works as the non-virtual C::operator() does not override the virtual functions in its base classes? How can I bring this to work (--without changing the name of C::operator())?
EDIT: As pointed out by several users, the answer is simply that the virtual-keyword in the derived class is redundant (whereas I thought leaving it out would prevent from inheriting). However, the goal I had in asking this -- namely a consistent interface throughout the dynamic and static inheritance hierarchy -- can be solved by using a non-virtual operator[] throughout and couple classes A and B by a virtual function apply:
struct A
{
void operator()() const
{
this->apply();
}
protected:
virtual void apply() const = 0;
};
template<typename Derived>
struct B : A
{
void operator()() const
{
static_cast<Derived const&>(*this).operator()();
}
protected:
virtual void apply() const override final
{
this->operator()();
}
};
struct C : B<C>
{
void operator()() const
{
//do something
}
};
int main()
{
C()();
}
If a function is declared virtual in a base class, then a function declared with the same name and parameter list is implicitly virtual in derived classes, whether or not you use the virtual keyword. You cannot make C::operator()() non-virtual.
A function in a derived class with the same signature as a virtual function in a base class overrides that virtual function from the base class. That makes it a virtual function, even if/though the declaration in the derived class doesn't use the virtual key word.
That can't be changed, so if you really need to have a function with the same name in a derived class that doesn't override the virtual function from the base class (and in the process, become virtual itself and in this case, violate the final in B) you'll need to change the signature of the function in the derived class. That can mean a different name, different parameter list, or different qualifiers. I'd treat the latter two with extreme caution though--the compiler will be able to sort out the mess you've made, but many human readers may (very easily) be surprised.
If I were reviewing such code, I'd probably cite this as a problem, and the author would need to provide very solid reasoning for why it was truly necessary to get it approved.
As an override (because it has the same signature as the virtual function in a base class), the override conflicts with the final specified in its base class.
One fix (or rather workaround) is to give that function a defaulted argument, so that it has a different type and hence not an override, and a better approach is to fix the design.

virtual tables and inheritance c++

i have a question regarding calling a function with virtual methods and multiple inheritence.
i have the following code:
#include<iostream>
using namespace std;
class A{};
class B:public A{};
class C:public B{};
class AA:public A{};
struct X
{
void f(A*) { std::cout<< "X::f(A*)\n";}
virtual void f(B*) { std::cout<< "X::f(B*)\n";}
void f(C*) { std::cout<< "X::f(C*)\n";}
virtual void f(C*) const { std::cout<< "const X::f(C*)\n";}
};
struct Y:public X {
virtual void f(B*) { std::cout<< "Y::f(B*)\n";}
void f(A*) { std::cout<< "Y::f(A*)\n";}
virtual void f(C*) const { std::cout<< "const Y::f(C*)\n";}
};
int main() {
Y* y=new Y();
y->f(new C);
}
I can't understand why this turns ambiguous and there are 2 candidates:
Y::f(B*)
Y::f(C*)
For an overloading function to be selected, it has to be the "best" at accepting each individual argument, including the implicit argument that becomes this. Best is defined in terms of the least conversions needed to convert the argument (in the caller) to the parameter (in the callee).
virtual void f(C*) const agrees perfectly with an argument of type C*, but the const qualifier at the end requires that this be converted from a non-const Y* to a Y const *. This is what the compiler is complaining about. If you cast
static_cast< Y const * >( y )->f(new C);
The problem goes away (although this isn't immediately illustrative since the extra qualification disqualifies the other overloads).
Note that all the overloads in X aren't even checked. The name resolution which finds all the overloads to be considered starts at the derived class and proceeds up the inheritance branches until it finds a matching name, and then it stops. To merge functions from multiple classes into one overload set, use a using declaration inside Y, using X::f;.
The actual solution to this problem is probably to introduce more matching overloads without const qualifiers at the end, so the const qualification of the calling pointer doesn't play such an unintuitive role.
Your overload for C is the only const member function.
y is non const and all overloads of f are acceptable, hence the call is ambiguous.
Ways to resolve the ambiguity:
Add a non const overload for C
Make y const
Make the overloads for A and B const
void f(C*) { std::cout << "X::f(C*)\n"; } in base class
is not visible due to name hiding.
use
using X::f;
in derived class, and it works as expected.

Why do function pointers break substitutability and std::function doesn't?

We have an usual class hierarchy:
class B
{
public:
int x;
B() : x(0) {}
virtual ~B() {}
};
class D : public B
{
public:
int y;
D() : y(0) {}
};
And a function that takes one argument - reference to a base class object.
void b_set(B& b)
{
b.x = 5;
}
Then, I want to create function pointer of type void (D&) and store b_set in it. This should be valid operation, as all objects legally passed to function pointer call must be also of type B. Yet it isn't allowed.
typedef void (*fp_d_mutator)(D&);
void fp_test(D& obj)
{
fp_d_mutator fun = b_set; //invalid conversion from 'void (*)(B&)' to 'fp_d_mutator {aka void (*)(D&)}
fun(obj);
}
#include <functional>
typedef std::function<void (D&)> stdfun_d_mutator;
void stdfun_test(D& obj)
{
stdfun_d_mutator fun = b_set; //works
fun(obj);
}
So...
How is that invalid conversion?
Why is that invalid conversion?
What could break if this was allowed?
How std::function avoids the problem in the first place?
A function that takes an argument of type B& is not a function that takes an argument of type D&. While D& is convertible to B&, they are not the same type. If you could store a pointer to a function that takes B& as a pointer to D&, how would the compiler know when to convert the argument? (Note that the conversion sometimes requires adjusting a pointer)
The difference in std::function is that the calling signature (here D&) is part of the function object's type, and the called signature (here B&) is part of the internal storage. So when you apply the function objects' operator() the code that implements operator()(D&) takes care of the conversion.