I couldn't understand the reason for not allowing modifiers such as const or volatile to nonmembers functions.
Following is the example code I tired
class A
{
private:
int var;
public:
int func();
};
int A::func()
{
// Some calculation on using var
int temp = var + 10;
return temp;
}
void func2( const A& tempObj ) const;
void func2( const A& tempObj )
{
std::cout << "temp obj called : " << tempObj.func() << std::endl;
}
int main()
{
A aobj;
aobj.func();
func2( aobj );
return 0;
}
which throws an compiler error error C2270: 'func2' : modifiers not allowed on nonmember functions for void func2( const A& tempObj ) const;
I also get another error error C2662: 'A::func' : cannot convert 'this' pointer from 'const A' to 'A &' for tempObj.func() in func2 here I was assuming that the member function func will be called without any errors.
const modifier states that a member function won't modify data members of the object the function belongs to.
It's like an assurance that calling that function on an object aobj won't modify the internal state of that object. So, assuming that aobj is declared const too, you will still be able to invoke that function on it; on the contrary, you would not be able to invoke non const function members.
If a function is not member of a class, it makes no sense to apply const modifier. On another language, it could have meant that the function wasn't able to modify global variables, maybe; but that language is not C++.
Imagine that there is a hidden parameter on each non-static member function:
int A::func(A* this) {...}
If you declare a member function const or volatile, that is added to that hidden parameter, pretty much like the following:
int A::func(const A* this) {...}
Some languages like python make the instance parameter on the member functions explicit, so there you write def func(self): inside a class definition to declare non-static functions.
A const qualification on a class method declares that the method doesn't modify any (non-mutable) member variables.
It therefore just doesn't make any sense to declare that on a non-member function because there are no member variables for it to modify.
The const qualification is very useful because it explicitly indicates that it's safe to call this method on a const variable without breaching the constness of that variable.
In C++, the member function modifiers apply to the object on which the function is being called. That is the use the language has for these modifiers.
Non-member functions have no such object, so the qualification would make no sense. One could imagine the language allowing cv-qualifying non-members as having no effect, but in my mind this would only be confusing. One could also imagine the cv-qualifiers having a different meaning for non-members, but the reality is what it is. That is the way the language was designed.
Related
I know that a const object can't call a non-const member function. It says so in the C++14 Standard (ISO/IEC 14882:2014) Section 9.3.2, Paragraph 3:
A cv-qualified member function can be called on an object-expression (5.2.5) only if the object-expression is as cv-qualified or less-cv-qualified than the member function.
Does this constraint make sense if the member function does not modify anything? Or if the member function modifies a mutable variable? For example:
class My_Class {
public:
mutable int value;
void function( int x ) const { value = x; } // Correct
//void function( int x ) { value = x; } // Not Correct
My_Class() : value(0) {}
};
int main(){
const My_Class obj;
obj.function( 1 );
return 0;
}
In this specific case, if the function is const, the program is correct and the function can modify a variable of the const object. If the function is not const, the program is not correct. So in the end, I need to write const to be able to modify something, which should be the opposite purpose of const.
Does anyone know why this rule is designed this way?
Does [Section 9.3.2, Paragraph 3 of] make sense if the member function does not modify anything? Or if the member function modifies a mutable variable?
Yes, it does. The caller of the function cannot in general know whether the function modifies any non mutable member. It knows whether the function is const or not, so the compiler can only make a decision based on that.
A non const function could modify the non mutable state, so you obviously may not call it on a const object. Whether the non const function does modify the state is irrelevant since it is an implementation detail that is not available when deciding if the call is allowed. In other words, constness is part of the interface of the function, while the implementation of the function is not part of the interface. The interface of the function is fully specified by its declaration.
An example:
struct C {
mutable int a;
int b;
void do_something();
};
const C c;
c.do_something();
Does it make sense to allow the call do_something? Does the fact that do_something might not modify b affect that? How could we assume that do_something does not modify b?
The answers are: It wouldn't make sense. It does not have an effect. There is no way we could make such assumption.
Writing a non const member function that doesn't modify any non mutable state - at least potentially or allow such modification indirectly by returning a non const reference / pointer to this - makes little sense, although the standard does permit doing so.
So in the end, I need to write const to be able to modify something, which should be the opposite purpose of const.
That might seem oxymoronic, but that is because it is an oversimplification. You need to write const to be able to modify the mutable state of a const object. The const that you write declares that you do not modify any non mutable state, and that declaration gives the permission to call it on const objects.
Your commented-out non-const function is still correct to use with non-const objects.
There is a fundamental misunderstanding in your question:
class My_Class {
public:
mutable int value;
void function( int x ) { value = x; } // Absolutely fine
My_Class() : value(0) {}
};
mutable does not mean "can only be modified in a const member function". It means "can be modified even in a const member function".
The mutable keyword,
Applies to non-static class members of non-reference non-const type and specifies that the member does not affect the externally visible state of the class (as often used for mutexes, memo caches, lazy evaluation, and access instrumentation). mutable members of const class instances are modifiable
You're questioning the validity of a C++ keyword. I feel the examples in this definition, provide positive proof that such a keyword is needed, and that mutable as imagined by the designers of the language is a boon to us.
In my code I would like to call different functions by the same name. So I used pointers, and I did work with static functions, now I would like to do the same with non-static functions and it doesn't work at all.
class Amrorder
: {
public:
....
void (*fkt)(real&, const real);
void fktAcPulse(real &rhoRef, const real y);
void fktAcPulseSol(real &rhoRef, const real y);
...
}
void Amrorder::initData(a)
{
...
switch(method){
case 2://
Amrorder::fkt=&Amrorder::fktAcPulse;
break;
case 222://
Amrorder::fkt=&Amrorder::fktAcPulse1d;
break;
}
...
for(int i=0; i<ng; ++i){
Amrorder::fkt(rhoRef, yRef);
...
}
...
}
The code is quiet big so I hope the part above is enough to understand what I want to do.
Thanks for your time!
It doesn't work because your fkt has type:
void (*)(real&, const real);
and you're trying to assign it to, e.g., &Amrorder::fktAcPulse, which has type:
void (Amrorder::*)(real&, const real);
Notice the difference. The latter is a pointer-to-member function, not just a pointer to function. These have different semantics. A pointer to function can just be called (e.g. fkt(a, b)), but a pointer to member function needs to be called on an object (e.g. (obj.*pm)(a, b)).
For simplicity, since you probably just want "something that I can call with a real& and a const real", you may want to consider the type-erased function object: std::function:
std::function<void(real&, const real)> fkt;
This can be initialized with any callable that matches the arguments, so you can assign it to a free function:
void foo(real&, const real) { ... }
fkt = foo;
A static member function:
struct S { static void bar(real&, const real) { ... } };
fkt = &S::bar;
Or a member function, as long as its bound:
fkt = std::bind(&Amrorder::fktAcPulse, this);
fkt = [this](real& a, const real b){ return this->fktAcPulse(a, b); };
The key is that you need an instance of Amrorder to call fktAcPulse, and using std::function lets you use either std::bind or a lambda to store that instance in with the functor itself.
The type of fkt declares a function pointer to a free-standing function or a static member function. But you want to assign a non-static member function pointer to it. So fkt needs to be of the type of a non-static member function pointer of class Amrorder. That type is spelled
void (Amrorder::*fkt)(real&, const real);
// ^^^^^^^^^^
When invoking a function pointer to a non-static member function, you need to specify on which object you want the member to be called (which normally defaults to this when calling a member function directly with its name).
The syntax for this is quite strange. It requires another pair of parentheses and depends on wether you call it on a pointer or an object itself:
(object.*functionPointer)(arguments);
(pointer->*functionPointer)(arguments);
So if you just want to call the function on the this pointer, you need to write
(this->*fkt)(rhoRef, yRef);
(Note that you don't need to specify the class in your code everywhere. Amrorder:: can be removed in front of every function name inside the definition of a member function of the same class.)
When you call a non-static method of a class, the compiler needs to know which instance of the class you want to execute against. So there is a hidden parameter in the call, which is a pointer to the instance.
So you need to write something like this:
Amrorder::fkt=bind( &Amrorder::fktAcPulse, this );
The title already says all. Let me expand a little nevertheless: I've class whose all attributes are const:
template< class perm = Perm16 >
class PermutationGroup {
public:
using StrongGeneratingSet = std::vector< std::vector< perm > >;
const std::string name;
const uint64_t N;
const StrongGeneratingSet sgs;
PermutationGroup(std::string name, uint64_t N, StrongGeneratingSet sgs) :
name(name), N(N), sgs(sgs) { assert(check_sgs()); };
bool check_sgs() const; // defined as const
bool is_canonical(vect v) const; // defined as const
[...]
};
Is it of any use to define all member function as const as well ? Or am I needlessly repeating myself ?
If you do not declare the member functions as const, you can't invoke them on const objects or objects referenced by a const reference. For example, the following won't work:
const PermutationGroup& group = PermutationGroup("foobar", 42, ...);
group.check_sgs(); // ERROR: can't invoke non-const function on const objects
Declaring your methods as const means that you can call them on a const-qualified object. It's not necessary to declare them const just because there are no mutable fields in the class, but in general, it's easier to write const-correct code if you always declare methods that don't modify anything as const.
Does a class with all attributes const need to have member function declared const as well?
Declaring a member variable const is different than declaring a member function const. When a member variable is declared const it cannot be modified. It can still be accessed by member functions even those not declared const, they just can't be modified.
Decalring a member function const is saying this function does not modify this object. The function is not allowed to change any member variable unless it's declared mutable. It also cannot call member functions that are not declared const as those functions would be allowed to modify the object.
Declaring member functions as const is important as it allows those functions to be called on constant instances of the class they belong to. Nosid provides a great example in their answer.
No it does not.
That been said, constness on behalf of the attributes implies constness on behalf of the instance, so even if a member function is non const it won't be able to behave as such (ie cause state mutation)
The other way around is not true though. For example
int myClass::example() const {
member = 1;
}
is the same as
int myClass::example() const {
this->member = 1;
}
and constness of the member function means constness of this pointer. This is slightly different from promising that the "raw bits" of the object's struct aren't going to change. For example, reference members can be modified by const member functions
To sum up : Declaring a member function as const becomes mandatory when it's to be used with a this pointer that is const. In your case, not declaring one as const would just be futile (and break the inspector / mutator semantics .. that being less of a deal).
say i have the following C++ class.
class C
{
int foo() const;
int & foo();
};
and i just call myC.foo(), i can see using the debugger that it calls the one with the reference.
why?
thanks!
It's likely because myC is a non-const value and hence the compiler is prefering the non-const method. The const method will only be preferred when accessed from a const value. For example
C value1;
value1.foo(); // int& foo();
const C value2;
value2.foo(); // int foo() const;
EDIT
Also, as Oli pointed out, overload resolution in C++ is not affected by the return type of the method. So it won't pick one of these signatures over the other based on the way in which the value is used.
Because myC must have not been an const obj.
C++ allows functions to be overloaded on the basis of the const keyword.
If a const object of the class is created only const member functions can be called through that object because they guarantee that they wont modify the state of the object.
a non const object can call both const as well as non const member functions but compilers gives preference to non const member functions over const member functions and hence the behavior in your case.
Too much C# and too little C++ makes my mind dizzy... Could anyone remind me what this c++ declaration means? Specifically, the ending "const". Many thanks.
protected:
virtual ostream & print(ostream & os) const
A const method will simply receive a const this pointer.
In this case the this pointer will be of the const ThisClass* const type instead of the usual ThisClass* const type.
This means that member variables cannot be modified from inside a const method. Not even non-const methods can be called from such a method. However a member variable may be declared as mutable, in which case this restriction will not apply to it.
Therefore when you have a const object, the only methods that the compiler will let you call are those marked safe by the const keyword.
The ending const means that the print function shouldn't be able to change the state of any of the members of the class it is declared in (and therefore cannot call any member functions of that class which are not also declared const).
In the example below, the print function in the class Foo cannot change any of the member variables of Foo (unless they are declared mutable), and cannot call any non-const functions in Foo.
class Foo {
public:
Foo(string value) { m_value = value; }
protected:
ostream & print(ostream & os) const {
m_value = string("foobar"); // won't compile
os << m_value;
return os;
}
private:
string m_value;
};
The const on the method declaration tells the compiler that the function is safe to call on a const object of the type the function is a member of. It also signals to the compiler that the function is not supposed to alter the state of the object and it will not be able to change any member variables that are not marked as mutable.
If you omit the const, this code will not work:
const Foo bar;
bar.print(std::cout); // Will fail to compile unless 'print' is marked const
You're declaring a protected virtual method named print which takes as a parameter a reference to an ostream and returns a reference to an ostream.
The const keyword means the method won't be able to alter the state of the object, the this pointer will be const.
A virtual method is a method whose behavior can be overridden within an inheriting class, basically the virtual keyword gives C++ its' ability to support polymorphism.
And finally if you don't know what is a reference go there
Comming from C# I suppose you know what protected means :)