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
Related
I'm following up on an earlier question, however my question pertains to type issues.
How do I assign a pointer to member function C::f() to the m pointer?
Does the member function need to be static?
#include <iostream>
using namespace std;
struct nullpt_t {
template<class T>
inline operator T*() const { return 0; }
template<class C, class T>
inline operator T C::*() const { return 0; }
};
nullpt_t nullpt;
struct C {
void f() {cout << "here" << endl;}
};
int main(void)
{
int *ptr = nullpt;
void (C::*m)() = nullpt;
// now assign m with member function f()?
}
All you have to do is take a pointer to the member function and assign it:
m = &C::f;
This only applies to non-static functions. Static functions have no instance associated with them, so you can take a standard function pointer to them. (Pointer-to-member is special because you have to supply an instance to dereference the pointer. Note that you don't have to do this when invoking a static member function normally.)
struct C {
void f() {cout << "here" << endl;}
static void g() {cout << "here static" << endl;}
};
int main() {
// Pointer-to-member-function (non-static)
void (C::*m)() = &C::f;
// Standard function pointer (static)
void (*n)() = &C::g;
}
#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);
}
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.
The following errors due to the const int specialization:
#include <iostream>
using std::cout;
using std::endl;
template <typename T> void g(T val)
{
cout << "unknown" << endl;
}
template <> void g(int && val)
{
cout << "int &&" << endl;
}
template <> void g(const int && val)
{
cout << "const int &&" << endl;
}
template <> void g(int & val)
{
cout << "int &" << endl;
}
template <> void g(const int & val)
{
cout << "const int &" << endl;
}
template <> void g(int val)
{
cout << "int" << endl;
}
template <> void g(const int val) //redefinition here
{
cout << "const int" << endl;
}
int main() {}
error: redefinition of 'g'
template <> void g(const int val)
^
Why are T& and T&& distinct from const T& and const T&& but T is not distinct from const T?
Because top-level const-ness of function parameters is an implementation detail of the function. For example, the following is valid:
// Prototype
void foo(int c);
// Implementation
void foo(int const c) { ... }
Since the argument is passed by value, the caller doesn't really care whether the function is going to modify its own private copy. Therefore, top-level const-ness is not part of the function signature.
Note that this only applies to top-level const-ness! int and int const are equivalent in a function prototype, as are int * and int * const. But int * and int const * are not.
When using arguments there are a few things to take into consideration, A: Not passing an arguement by reference is creating its own new variable, and B: Passing by reference is using the same variable as the argument with a different name
This is important because:
void doStuff (const int x)
{
//x is its own constant variable
}
Whereas
void doStuff (const int& x)
{
//because x is the same variable that was used when calling this function
//x can be modified outside of this function, but not inside the function
//due to the const modifier
}
The const modifier on the 2nd function allows you to do things like this:
int main ()
{
const int x = 10;
doStuff(x)
}
References are used to modify a variable in another function and to save memory on the stack, this saves memory because it uses a pointer rather than a newly created variable, so anything larger than an int will save memory by calling using a reference even if you arent modifying it in the function
Now if i am correct the && operator should not be used in an argument because this is a boolean operator and does not modify the argument type. It should only be used in conditions but wouldnt create a syntax error when compiling (compiler thinks its a reference of type [type] &) but that does nothing to the way the variable is used besides taking slightly longer for the computer to process
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