I have seen a code portion in the boost example which is used to construct a state machine. What confused me is the two member functions ElapsedTime()? Is this allowed for the two functions to have the same signatures such as function name and parameters type?
I have googled a lot but without any luck to find relevant info about this. Any advice on this would be greatly appreciated.
struct Active : sc::simple_state< Active, StopWatch, Stopped >
{
public:
typedef sc::transition< EvReset, Active > reactions;
Active() : elapsedTime_( 0.0 ) {}
double ElapsedTime() const { return elapsedTime_; }
double & ElapsedTime() { return elapsedTime_; }
private:
double elapsedTime_;
};
Signature of a function is defined by the name and by the argument types.
You have two functions with the same name, but they do not get the same arguments!
You might wonder how could it be?
So, each member function gets another parameter implicitly: this is the "this" pointer. A pointer to the object who called that method.
When you add const in the end of the method, you specify the "this" argument as a const pointer to const. In the other method (without the const), the type of "this" is just const pointer.
Hence, you have two methods with different signature, and there is no problem at all.
They do not have the same signatures - one is const and another one is not. Constness is part of member function signature.
The signatures are different because one has const qualifier.
http://www.cprogramming.com/tutorial/const_correctness.html
Is this allowed
This usage is allowed as over.load#2.2 states:
Member function declarations with the same name and the same parameter-type-list cannot be overloaded if any of them is a static member function declaration ([class.static]). Likewise, member function template declarations with the same name, the same parameter-type-list, and the same template parameter lists cannot be overloaded if any of them is a static member function template declaration. The types of the implicit object parameters constructed for the member functions for the purpose of overload resolution ([over.match.funcs]) are not considered when comparing parameter-type-lists for enforcement of this rule. In contrast, if there is no static member function declaration among a set of member function declarations with the same name and the same parameter-type-list, then these member function declarations can be overloaded if they differ in the type of their implicit object parameter. [ Example: The following illustrates this distinction:
(end quote)
Now, in your example the first overload has a const qualifer which means that its implicit object parameter has type const Active& while the second overload has no const qualifer meaning that its implicit object parameter is of type Active&. Moroever, there is no static member function declaration for ElapsedTime with the same paremeer-type-list. Hence using the above quoted statement, this means that the given usage is allowed.
Note
Note that the currently accepted answer is technically incorrect because it claims that this is a const pointer to const. But in reality the standard specifies that inside a const qualified member function the this pointer is of type const X* while inside a non-const qualified member function the this pointer is of type X*.
Related
I am using the gtkmm library on linux to draw a simple menu for my GUI.
In the below code the compiler complained about unable to resolve address
sigc::mem_fun(*this, AppWindow::hide)));
^
appwindow.cpp:15:41: note: could not resolve address from overloaded function
But when I insert the & it compiles fine
m_menu_app.items().push_back(MenuElem("Quit",
sigc::mem_fun(*this, &AppWindow::hide)));
What difference does it make here? Isn't the hide function just an address in the first place?
This is the exact definition of the function-to-pointer conversion, [conv.func]:
An lvalue of function type T can be converted to a prvalue of type
“pointer to T.” The result is a pointer to the function.55
55) This conversion never applies to non-static member functions because an lvalue that refers to a non-static member function
cannot be obtained.
Thus the decay that we see with normal, non-member functions1 doesn't apply and you need to explicitly take the address.
I.e.
void f();
struct A {
void f();
static void g();
};
auto a = f; // Ok: auto deduced as void(*)()
auto b = A::f; // Error: A::f not an lvalue, auto cannot be deduced
auto c = A::g; // Ok: auto deduced as void(*)()
1 Or static member functions.
For global (non-member) functions, the name of the function evaluates to the address of that function except when passed to the & operator, so you can (for example) assign to a pointer to a function either with or without the & equivalently:
int f() {}
int (*pf1)() = f;
int (*pf2)() = &f;
So, in this case there's really no difference between the two.
For member functions1, however, the rules are a bit different. In this case, the & is required; if you attempt to omit the &, the code simply won't compile (assuming a properly functioning compiler, anyway).
There's no particular reason this would have to be the case--it's just how Bjarne decided things should be. If he'd decided he wanted the name of a member function to evaluate to a pointer to a member (equivalent to how things work for non-member functions) he could have done that.
1. Other than static member functions, which mostly act like non-member functions.
When a function is a non-static member function of a class, then it is necessary to use the form &ClassName::functionName when a pointer to the member function is expected in an expression.
When a function is a static member function of a class, both ClassName::functionName and &ClassName;:functionName can be used when a pointer to a function is expected in an expression.
When a function is a global, i.e. non-member, function, both functionName and &functionName can be used when a pointer to a function is expected in an expression.
I'm currently working on material from my data structures class, which involves an exercise where we attempt to define a class mimicking a vector so we can get an understanding of what's going on underneath the hood. Everything made sense until I realized that there are two definitions foroperator[]. In context:
typedef unsigned int size_type;
T& operator[] (size_type i) { return m_data[i]; }
const T& operator[] (size_type i) const { return m_data[i]; }
First question: why is it necessary to have two definitions of operator[]?
Second question: why doesn't this throw a multiple definitions error?
Sorry if anything is vague or seems obvious. I'm new to C++, my only other experience being in Java. Thanks!
This is a common C++ pattern.
The const member function (that is, the one with the keyword const after the prototype) applies when *this is const; in other words, if it is used with a const object. Since *this is const, it's reasonable to assume that it cannot be modified, so operator[] must return a const reference.
The other member function would apply to any object, but since it is less specific than the const one, it only applies if *this is not const. In that case, it is presumably possible to modify the returned reference (object[3] = new_value;), so the return type is not const.
First question: why is it necessary to have two definitions of
operator[]?
Those definitions differ with their const-qualifier (and result type). One of them is const and returns const reference to internal data. It is used if your container is declaread as const, so that reference to it's contents are const as well. If your contianer is not const, non-const operator is used so that internal data can be modified.
Second question: why doesn't this throw a multiple definitions error?
Because const-qualifier is a part of function prototype, which means that void foo(); and void foo() const; are actually two diffrent methods. It allows overloading based on const qualifier of object being used to call the method.
why is it necessary to have two definitions of operator[]?
It's necessary if you want one that you can modify its value (e.g. obj[i] = value) and the other cannot (with const).
why doesn't this throw a multiple definitions error?
Based on $9.3.1/3 states-
"A nonstatic member function may be declared const, volatile, or const volatile. These cvqualifiers affect the type of the this pointer (9.3.2). They also affect the function type (8.3.5) of the member function; a member function declared const is a const member function, a member function declared volatile is a volatile member function and a member function declared const volatile is a const volatile member function."
That said, you can overload a function by using one of those qualifiers, e.g.:
void func();
void func() const;
Each function can be recognized by what you can call signature, when you declare a function in C++ you write the signature of the function, a signature looks like
qualifiers T ( qualifiers U u ) qualifiers;
############ ------------------ ::::::::::
so the signature it's composed of the 2 part that I outlined with # and -, the part with # is the return type and the part - is the description for the arguments accepted by the function.
The point is that if you write the same signature with different qualifiers, C++ still considers this the re-declaration/re-definition of the same function, so qualifiers are part of the signature but when comparing multiple declarations/definitions of functions with the same name they are virtually dropped by your compiler.
You should read more about qualifiers, I simplified the concept here.
You can also add more qualifiers after the signature, the part I outlined with :, to declare some properties about the way your function works, for example const means that you declare that your function doesn't modify the variables that it can access .
While writing the following function abs, I get the error:
non-member function unsigned int abs(const T&) cannot have cv-qualifier.
template<typename T>
inline unsigned int abs(const T& t) const
{
return t>0?t:-t;
}
After removing the const qualifier for the function there is no error. Since I am not modifying t inside the function the above code should have compiled. I am wondering why I got the error?
Your desire not to modify t is expressed in const T& t. The ending const specifies that you will not modify any member variable of the class abs belongs to.
Since there is no class where this function belongs to, you get an error.
The const modifier at the end of the function declaration applies to the hidden this parameter for member functions.
As this is a free function, there is no this and that modifier is not needed.
The t parameter already has its own const in the parameter list.
The cv-qualifier on a member function specifies that the this pointer is to have indirected type const (or volatile, const volatile) and that therefore the member function can be called on instances with that qualification.
Free functions (and class static functions) don't have a this pointer.
As we all know, const keyword followed after the argument list indicates that this is a pointer to a pointer constant.
There is a non-member function, it does not belong to the class, so add const opposite end error occurs.
Solution to the problem: is to either become a class member function or remove the const keyword const opposite end
Today I got a problem. I am in the need of a static member function, const is not a must but a better. But, I didn't succeed in my efforts. Can anybody say why or how?
When you apply the const qualifier to a nonstatic member function, it affects the this pointer. For a const-qualified member function of class C, the this pointer is of type C const*, whereas for a member function that is not const-qualified, the this pointer is of type C*.
A static member function does not have a this pointer (such a function is not called on a particular instance of a class), so const qualification of a static member function doesn't make any sense.
I agree with your question, but unfortunately the C++ is designed that way. For example:
class A {
int i; //<--- accessed with 'this'
static int s; //<---- accessed without 'this'
public:
static void foo () const // <-- imaginary const
{}
};
As of today, the const is considered in context of this. In a way, it's narrow. It can be made broader by applying this const beyond this pointer.
i.e. the "proposed" const, which may also apply to static functions, will restrict the static members from any modification.
In the example code, if foo() can be made const, then in that function, A::s cannot be modified. I can't see any language side effects, if this rule is added to standard. On the contrary, it's amusing that why such rule doesn't exist!
It is unfortunate that C++ doesn't accept it as per design but logically there are few use cases in which it validates well.
A function which is class level valid(static) might not change any static data, may be it will just query data should be const.
May be it should be like
if(Object)
MakeThisConstant()
else
MakeStaticDataConstant() // Only in the scope but static data cannot be constant so may be it should in some scenarios
Without getting into the details, it's because there may or may not be an object modified by the function, so const is ambiguous to the compiler.
Recall that const keeps objects constant, but there may or may not be an object here to keep constant.
A 'const member function' is not
allowed to modify the object it is called on, but static member
functions are not called on any object.
It is used directly by scope resolution operator.
Thus having a const static member function makes no sense, hence it is illegal.
I am reading some C++ text from the address https://cs.senecac.on.ca/~chris.szalwinski/archives/btp200.081/content/overl.html.
in the first lines, they say:
The signature of a member function consists of:
the function name,
the data types of its parameters,
the order of the parameters and
possibly
the const status of the function.
I don't understand what they mean by saying "the const status of the function".
Can anyone elaborate on that, please?
Thanks.
In C++, you can declare a member function of a class to be const, by appending that keyword to its signature (for instance, int MyClass:doSomething(int param) const {...}). Doing so guarantees that the function won't change the (non-mutable) members of the class object on which the function is called - and hence it can be called with const instances of that class.
It is permissible to have two different member functions for a class whose signature differs only in whether they are declared const or not.
They mean to sum up the items of where functions must differ in order to be put into the same class scope. The const at the end is:
struct A {
void f();
void f() const;
};
These are valid overloads. The first is called if you call f on a A, and the second is used if you call it on a const A:
A a;
a.f(); // takes first
A const& b = a;
b.f(); // takes second
Note that the term "signature" is misused here. The signature of a function is more broad, and includes also the class of which a function is a member of. A signature uniquely identifies a function.
Declaring a member function as const tells the compiler that the member function will not modify the object's data and will not invoke other member functions that are not const.
The compiler will check to make sure that you really don't modify the data. You can call a const member function for either a const or a non-const object, but you can't call a non-const member function for a const object (because it could modify the object).
You can read more about constness in C++ here.