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.
Related
This question already has answers here:
Meaning of 'const' last in a function declaration of a class?
(12 answers)
Closed 3 years ago.
I got a book, where there is written something like:
class Foo
{
public:
int Bar(int random_arg) const
{
// code
}
};
What does it mean?
A "const function", denoted with the keyword const after a function declaration, makes it a compiler error for this class function to change a member variable of the class. However, reading of a class variables is okay inside of the function, but writing inside of this function will generate a compiler error.
Another way of thinking about such "const function" is by viewing a class function as a normal function taking an implicit this pointer. So a method int Foo::Bar(int random_arg) (without the const at the end) results in a function like int Foo_Bar(Foo* this, int random_arg), and a call such as Foo f; f.Bar(4) will internally correspond to something like Foo f; Foo_Bar(&f, 4). Now adding the const at the end (int Foo::Bar(int random_arg) const) can then be understood as a declaration with a const this pointer: int Foo_Bar(const Foo* this, int random_arg). Since the type of this in such case is const, no modifications of member variables are possible.
It is possible to loosen the "const function" restriction of not allowing the function to write to any variable of a class. To allow some of the variables to be writable even when the function is marked as a "const function", these class variables are marked with the keyword mutable. Thus, if a class variable is marked as mutable, and a "const function" writes to this variable then the code will compile cleanly and the variable is possible to change. (C++11)
As usual when dealing with the const keyword, changing the location of the const key word in a C++ statement has entirely different meanings. The above usage of const only applies when adding const to the end of the function declaration after the parenthesis.
const is a highly overused qualifier in C++: the syntax and ordering is often not straightforward in combination with pointers. Some readings about const correctness and the const keyword:
Const correctness
The C++ 'const' Declaration: Why & How
Consider two class-typed variables:
class Boo { ... };
Boo b0; // mutable object
const Boo b1; // non-mutable object
Now you are able to call any member function of Boo on b0, but only const-qualified member functions on b1.
Bar is guaranteed not to change the object it is being invoked on. See the section about const correctness in the C++ FAQ, for example.
Similar to this question.
In essence it means that the method Bar will not modify non mutable member variables of Foo.
I always find it conceptually easier to think of that you are making the this pointer const (which is pretty much what it does).
Function can't change its parameters via the pointer/reference you gave it.
I go to this page every time I need to think about it:
http://www.parashift.com/c++-faq-lite/const-correctness.html
I believe there's also a good chapter in Meyers' "More Effective C++".
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'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 .
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.
This question already has answers here:
c++ access static members using null pointer
(5 answers)
Closed 8 years ago.
class Foo {
public:
static const int kType = 42;
};
void Func() {
Foo *bar = NULL;
int x = bar->kType;
putc(x, stderr);
}
Is this defined behavior? I read through the C++ standard but couldn't find anything about accessing a static const value like this... I've examined the assembly produced by GCC 4.2, Clang++, and Visual Studio 2010 and none of them perform a dereference of the NULL pointer, but I'd like to be sure.
You can use a pointer (or other expression) to access a static member; however, doing so through a NULL pointer unfortunately is officially undefined behavior. From 9.4/2 "Static members":
A static member s of class X may be
referred to using the qualified-id
expression X::s; it is not necessary
to use the class member access syntax
(5.2.5) to refer to a static member. A
static member may be referred to using
the class member access syntax, in
which case the object-expression is
evaluated.
Based on the example that follows:
class process {
public:
static void reschedule();
};
process& g();
void f()
{
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
The intent is to allow you to ensure that functions will be called in this scenario.
I believe that the actual value of the type is not used at all when calling
bar->kType
since kType is static, and bar is of type Foo it is the same as calling
Foo::kType
which you should really be doing anyway for clarity.
Calling bar->kType gives a compiler warning on most platforms for this reason.
Apart from the issue about accessing through the NULL pointer, there is another subtle issue in the code
$9.4.2/2 - "The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition."
$9.4.2/4- "If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer."
class Foo {
public:
static const int kType = 42;
};
int const Foo::kType;
void Func() {
Foo *bar = NULL;
int x = bar->kType;
putc(x, stderr);
}
So, yet one more reason for UB in the OP code.
Even if it worked it is awful code.
In serious programming you code not only for yourself, but also for others who will maintain your code.
Playing tricks like this must be avoided, because you respect your colleagues.
One consequence of this code: whether the pointer is NULL or not is even not at question, but it implies that this member kType may not be a plain non-static member of the class. Sometimes classes are big (this is evil too) and one cannot always recheck the definition of each and every variable.
Be rigorous. And call all your static members only this way:
Foo::kType
Another possibility is to follow a coding convention that let know that the member is static, for example, a s_ prefix for all classes static members:
Foo::s_kType
There is a higher rule so to speak which basically says - don't even think about compiling things that are provably not used. Advanced template programming depends on this a lot, so even if it might be a bit gray-zonish when a compiler clearly sees that the result of a construct is not used it's just going to eliminate it. Especially when it's provably safe like in this case.
You may want to try a few variants if you want - like making pointer a param of a function, result of a function, leaving a pointer uninitialized (best chance for triggering compiler complaint), doing a straight cast of 0 (best chance of being conplaint-free).