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.
Related
I'm having a problem with using C++ overloading and was wondering if anybody could help.
I'm trying to overload functions so that its argument accept reference and literal respectively.
For example, I want to overload func1 and func2 to func:
int func1 (int literal);
int func2 (int &reference);
and I want to use func in this situations:
func(3); // call func1
int val = 3;
func(val); // I want func2 to be called, but ambiguous error
Is there any way to overload these functions?
thanks! Any help would be appreciated!
sorry for poor english.
Literals and temporary values can only be passed as const references while named values will prefer a non-const reference if available. You can use this with either & or && to create the 2 overloads.
For why and more details read up on rvalues, lvalues, xvalues, glvalues and prvalues.
The code below shows which function overload will be used for the most common cases, the first 2 being the ones you asked about:
#include <iostream>
void foo1(int &) { std::cout << "int &\n"; }
void foo1(const int &) { std::cout << "const int &\n"; }
void foo2(int &) { std::cout << "int &\n"; }
void foo2(const int &) { std::cout << "const int &\n"; }
void foo2(int &&) { std::cout << "int &&\n"; }
void foo2(const int &&) { std::cout << "const int &&\n"; }
int bla() { return 1; }
int main() {
int x{}, y{};
std::cout << "foo1:\n";
foo1(1);
foo1(x);
foo1(std::move(x));
foo1(bla());
std::cout << "\nfoo2:\n";
foo2(1);
foo2(y);
foo2(std::move(y));
foo2(bla());
}
Output:
foo1:
const int &
int &
const int &
const int &
foo2:
int &&
int &
int &&
int &&
#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);
}
Take a look at this simple array class
class Array {
const unsigned int _size;
int _array[100];
public:
Array() : _size(100) {
for(unsigned int i = 0; i < _size; i++)
_array[i] = 0;
}
int& operator[](unsigned int index) {
cout << "normal operator[].\n";
return _array[index];
}
const int& operator[](unsigned int index) const {
cout << "const operator[].\n";
return _array[index];
}
};
int main()
{
Array a;
a[3] = 1;
cout << a[3] << "\n";
system("pause");
return 0;
}
The "normal operator[]" line is executed twice, though I would expect the second call (cout << a[3] << "\n";) to be using the const version of the overloaded operator, because it doesn't change the array itself.
Why is that? Is there a way to force the const version to be called as I wish?
When you have an overloaded const version of a method, the const version will be called when the object is const. For example:
#include <iostream>
using namespace std;
class MyClass
{
public:
void foo()
{
cout << "foo()" << endl;
}
void foo() const
{
cout << "foo() const" << endl;
}
};
int main()
{
MyClass a;
const MyClass b;
a.foo();
b.foo();
return 0;
}
will call the normal foo() for the object a, and the const version for the object b.
In your case, you just have to avoid trying to assign to the const version. For example:
Array a;
const Array b;
a[3] = 1;
// b[3] = 1; // error
cout << a[3] << "\n";
cout << b[3] << "\n";
works fine. But if you try to make the assignment to b, you get a compile error.
std::ostream &operator<<(int x) doesn't take its parameter as const (because const isn't useful when passing by value), so the non-const operator[] can be called.
So, when will const operator[] be called?
It is true that a const vector variable declaration is almost always useless aside from some edge cases. The primary reason const operator[] is important, and the most often you will see it used, is calling it on a reference parameter.
int readStuff(const std::vector<int> &dontMutateMe) {
return dontMutateMe[42]; // const
}
Constant reference parameters are valuable, and this code wouldn't work without const operator[].
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