supposed there are two overloaded member function(a const version and a non-const version) in the String class:
char & String::operator[](int i) //Version 1
{
cout<<"char & String::operator[](int i) get invoked."<<std::endl;
return str[i];
}
const char & String::operator[](int i) const //Version 2
{
cout<<"const char & String::operator[](int i) const get invoked."<<std::endl;
return str[i];
}
and there is a test code fragment
int main(){
String a;
cout<<a[0]<<endl; //Line 1
a[0]='A'; //Line 2
}
How does the compiler decide which function to call? I found that Version 1 always got called when I run the program. Could anybody tell me why it is? And how can Version 2 got called?
If a is const, the second overload will get called.
int main(){
const String a;
cout<<a[0]<<endl; // would call const version
a[0]='A'; // will not compile anymore
}
If the object is const, the the const member function will be called. If the object is non-const the non-const member-function is called.
Exception
If their is only the const function, it is called in any case.
#include <iostream>
using namespace std;
class Foo {
public:
void print() {
cout << "Foo non-const member function\n";
}
void print() const {
cout << "Foo const member function\n";
}
};
class Bar {
public:
void print() const {
cout << "Bar const member function\n";
}
};
int main() {
Foo foo_non_const;
const Foo foo_const;
Bar bar_non_const;
const Bar bar_const;
foo_non_const.print();
foo_const.print();
bar_non_const.print();
bar_const.print();
return 0;
}
$ ./blah
Foo non-const member function
Foo const member function
Bar const member function
Bar const member function
Related
#include <iostream>
struct A
{
void f() const &
{
std::cout << "A::f()&" << std::endl;
}
void f() const &&
{
std::cout << "A::f()&&" << std::endl;
}
};
struct B
{
void f() const &
{
std::cout << "B::f()&" << std::endl;
}
};
int main()
{
A{}.f();
B{}.f();
}
The output is:
A::f()&&
B::f()&
Note that void B::f() const && doesn't exist.
To me, a temporary object of B calls B::f, void B::f() const && should be chosen, or a compiler error should be raised.
Why is void B::f() const & chosen in such a case?
Because void B::f() const && doesn't exist, the next best candidate is selected which is your void B::f() const &. The rvalue will bind to a const &. If you remove the const you will notice you will get a compile error as the rvalue cannot bind to a non-const reference. The example on cppreference/overloadresolution shows it perfectly.
int i;
int f1();
int g(const int&); // overload #1
int g(const int&&); // overload #2
int j = g(i); // lvalue int -> const int& is the only valid conversion
int k = g(f1()); // rvalue int -> const int&& better than rvalue int -> const int&
This is no different for the implicit this argument in your examples.
To me, a temporary object of B calls B::f, void B::f() const && should be chosen, or a compiler error should be raised.
if this was the case then code like the following would break without a [const] rvalue reference overload existing.
void f(const int& i)
{
std::cout << i;
}
int main()
{
f(3);
}
Consider the following code.
class MyClass1
{
public:
MyClass1(const int& i)
{
myVar = i;
}
const int& get() const
{
std::cout<<"Inside 1 \n";
return myVar;
}
int get()
{
std::cout<<"Inside 2 \n";
return myVar;
}
private:
int myVar;
};
class MyClass2
{
public:
MyClass2(const int& i)
{
myVar = i;
}
const int& get()
{
std::cout<<"Inside 3 \n";
return myVar;
}
int get() const
{
std::cout<<"Inside 4 \n";
return myVar;
}
private:
int myVar;
};
int main(int argc, char* argv[])
{
MyClass1 myClass1(10);
int tmp1 = myClass1.get();
const int& tmp2 = myClass1.get();
MyClass2 myClass2(10);
int tmp3 = myClass2.get();
const int& tmp4 = myClass2.get();
return 0;
}
The output showed the following.
Inside 2
Inside 2
Inside 3
Inside 3
For "const int& tmp2 = myClass1.get();" I expected that it will print call "const int& get() const" in MyClass1. To my surprise, it called "int get()" in both the cases in MyClass1.
In MyClass2, I swapped the "const" and then I found that in the function calls it called "const int& get()".
Why is it happening like this?
For "const int& tmp2 = myClass1.get();" I expected that it will print call "const int& get() const" in MyClass1.
You don't explain why you expect this, but you certainly shouldn't. There are two get functions that take no parameters, one const and the other not. Since myClass1 is not const, the function that is not const is called.
Were it not this way, there would be no point in allowing two class member functions that have the same name and take the same parameters to differ only in that one is const and the other isn't.
#include <functional>
#include <iostream>
struct Foo {
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_+i << '\n'; }
int get_num(int i) { return num_;}
void set_num(int i) { num_ = i;}
int num_;
};
int main() {
std::function<int(const Foo *, int)> f_get_num;
f_get_num = &Foo::get_num;
return 0;
}
This will generate a error, error: invalid conversion from ‘const Foo*’ to ‘Foo*’ [-fpermissive] at line f_get_num = &Foo::get_num. Foo::get_num type is int (Foo:: *fp)(int). Can anybody explain it? Thanks.
You cannot call non-const functions on const objects. You can pass const Foo* to f_get_num, but Foo::get_num takes non-const implicit this.
The following two calls are just as illegal:
Foo foo;
Foo const* const_ptr = &foo;
const_ptr->get_num(42);
f_get_num(const_ptr, 42); // results in const_ptr->get_num(42)
You can declare your get_num to be const:
int get_num(int i) const { return num_;}
And then your code will work correctly.
The other way is to make your f_get_num take non-const parameter, but that's not the way to go when your function is a getter and shouldn't modify the object.
std::function<int(Foo*, int)> f_get_num;
f_get_num = &Foo::get_num;
struct A {
void foo(int i, char& c) {
cout << "foo int char&" << endl;
}
void foo(int& i, int j) const {
cout << "const foo int& int" << endl;
}
};
int main() {
A a;
const A const_a;
int i = 1;
char c = 'a';
a.foo(i,i);
}
Will be printed:
const foo int& int
I dont understand why.
Why "const foo int& int" wont be printed?
I thought that constant Object can only call constant methods, and none const can call none const.
You misunderstood member-const.
A normal object can have any member function invoked on it, const or otherwise.
The constraint is that your const_a would not be able to have the non-const member function invoked on it. Unfortunately, you did not test that.
class arbit
{
int var;
public:
int method1();
int method1() const;
};
Why does g++ does not give warning while declaring the same function twice here ?
Because one is const and the other is not. These are different overloads, with different signatures. One or the other gets called, depending on whether the object you call it on is const.
Example:
arbit x;
x.method1(); // calls the non-const version
arbit const &y = x;
y.method1(); // calls the const version
You should declare a method as const if it doesn't modify the (visible) state of the object. That allows you to hand out const arbit objects, and be certain¹ that someone won't accidentally modify them.
For example, you would make a function setValue non-const (because it modifies the object), but getValue would be const. So on a const object, you could call getValue but not setValue.
¹ When there's a will, there's a way, and it's called const_cast. But forget that I ever told you.
You can also overload with volatile modifier and a combination of the two: const volatile
#include <iostream>
using namespace std;
class foo {
public:
void bar() { cout << "bar()" << endl; }
void bar() const { cout << "bar() const" << endl; }
void bar() volatile { cout << "bar() volatile" << endl; }
void bar() const volatile { cout << "bar() const volatile" << endl; }
};
int main() {
foo f;
f.bar();
foo const f_const;
f_const.bar();
foo volatile f_volatile;
f_volatile.bar();
foo const volatile f_const_volatile;
f_const_volatile.bar();
}
That will output:
bar()
bar() const
bar() volatile
bar() const volatile