C++ Library Extensions 2022.12.09
To help learn modern C++ programming
const_pointer.cpp
Go to the documentation of this file.
1
2#include <tpf_types.hpp>
3#include <tpf_output.hpp>
4
5#ifdef __FUNCSIG__
6 #define FUNCTION_NAME __FUNCSIG__
7#else
8 #define FUNCTION_NAME __PRETTY_FUNCTION__
9#endif
10
11/*
12 1. We will define a macro for function name.
13 In case of MSVC or Microsoft Visual C++ Compiler, the macro
14 __FUNCSIG__ is defined inside of a function. This macro is
15 defined only inside of a function.
16
17 In case of GNU g++/clang++, the macro __PRETTY_FUNCTION__ is
18 defined inside of a function.
19
20 For compatibility for Microsoft Visual C++ and GNU g++/clang++,
21 we defined a common macro named FUNCTION_NAME
22
23 2. We will learn how to use FUNCTION_NAME macro.
24
25 3. According to the Creator of C++, Bjarne Stroustrup, in his book
26 The C++ Programming Language, he mentions "the interface" of a class.
27
28 "The interface" of a class means the public member functions. In our MyClass,
29 the interface of this class are
30
31 int& get_data();
32 const int& get_data() const
33
34 He also mentions "the implemenation" of a class. By the "implementation," he means
35 the data members or data fields. In our case of MyClass,
36
37 "the implementation" is
38
39 int m_data;
40
41 And, I will call member functions without trailing "const" specifier as "non-const" member function.
42 So,
43 int& get_data() is non-const member function, or non-constant inferface.
44
45 I will call the member function with trailing "const" specifier as "const" member functions.
46 In our case,
47
48 const int& get_data() const is a const member function, or constant interface.
49
50 "implementation", "interface", "non-const" member function or non-constant interface,
51 "const" member function or const interface.
52
53 4. The type of "this" in non-const member functions is
54
55 ClassType* const; // this is constant pointer that points to non-const object.
56
57 The type of "this" in const member functions is
58
59 const ClassType* const; // this is constant pointer that points to const object.
60
61 "const" in "ClassType* const" means we cannot modify the value of the pointer itself.
62 It does not mean we cannot modify the value the const pointer is pointing to.
63
64 The "trailing const" in "const ClassType* const" means that we cannot modify
65 the value of the pointer itself. It does not mean we cannot modify the value of the object
66 the constant pointer is pointing to.
67
68 In this case, the "leading const" in "const ClassType* const" means that we cannot modify
69 the value of the object that the const pointer is pointing to.
70
71 In a non-const member functions,
72 such as int& get_data(), the type of "this" is "MyClass* const" which means
73 the const pointer "this" points to a non-const object, so we can modify the value of the object
74 that "this" pointer is pointing to. That is, we can alter the state or implementation of the object
75 in the non-const member functions.
76
77 In a const member functions,
78 such as const int& get-data() const, the type of "this" is "const MyClass* const" which means
79 the const pointer "this" points to a const object, so we cannot modify the value of the const object
80 that "this" pointer is pointing to. That is, we cannot alter the state or implementation of the object
81 in the const member functions.
82
83 5. Let me clear away the term "const pointer."
84
85 6. References and pointers in machine-level, they are synonymous or even identical.
86 If you want to return reference or pointer, that object that you want return as a reference or a pointer
87 SHOULD OUTLIVE its enclosing scope.
88
89 7. To return an object as a reference or a pointer, the object should outlive its enclosing scope.
90
91 That being said "outlive its enclosing scope," we cannot return a local stack-oriented object
92 either as a reference or a pointer.
93
94
95
96
97
98
99*/
100class MyClass
101{
102 private:
103 int m_data{};
104
105 public:
106
107 MyClass() = default;
108
109 // returns lvalue reference, and does not have trailing const specifier
110 int& get_data() // no const specifier here
111 {
112 tpf::console cout;
113 auto nl = tpf::output::nl();
114 cout << "Inside the function: " << FUNCTION_NAME << nl;
115 cout << "The type of \"this\": " << Tpf_GetTypeCategory(this) << nl;
116 return this->m_data;
117 }
118
119 // it returns const lvalue reference, and has trailing const specifier
120 const int& get_data() const // const here
121 {
122 tpf::console cout;
123 auto nl = tpf::output::nl();
124 cout << "Inside the function: " << FUNCTION_NAME << nl;
125 cout << "The type of \"this\": " << Tpf_GetTypeCategory(this) << nl;
126
127 return this->m_data;
128 }
129
130 // it returns pure rvalue int, also has const specifier
131 // int get_data(int offset) const // trailing const specifier
132 // {
133 // return this->m_data + offset;
134 // }
135
136 // it returns pure rvalue int, also has const specifier
137 int get_data(int offset) const // trailing const specifier
138 {
139 int r = this->m_data + offset;
140
141 return r; // we are returning a local stack variable
142 // so, we cannot return a reference.
143 }
144
146 {
147 std::cout <<"Okay, I am safely destroyed..." << std::endl;
148 }
149};
150
152{
153 MyClass nco; // non-const MyClass object
154
155 nco.get_data(); // int& get_data() is called
156
157 const MyClass co; // const MyClass object
158
159 co.get_data(); // const int& get_data() const is called
160}
161
163{
164 MyClass nco; // non-const object;
165
166 // ptr is "non-const pointer in true sense of const"
167 // ptr is a pointer that points to a const object
168 const MyClass* ptr; // is this a const pointer?
169 // SSTS: this is not a const pointer.
170 //
171 // But we the C++ programmers call it "const pointer"
172 // why?
173
174 // MyClass* const cptr; // does this work?
175 // NO! It does not work. Why?
176 //
177 // In our previous episode, we learned that anything that is "const" or "reference"
178 // should be initialized at definition.
179 // We have not initialized it at definition, so the C++ compiler does not compile it at all.
180
181 // cptr is "a const pointer in true sense of const"
182 // cptr is a const pointer that points to a non-const object.
183 MyClass* const cptr = &nco; // we now initialized const pointer cptr with non-const object nco.
184
185 // When we say "const pointer," do we mean "a pointer that points to a const object, as with ptr,"
186 // or "a const pointer that points to a non-const object as with cptr?"
187 // which one do we mean "by const pointer?"
188
189 /*
190 Pointers are meant to be used by freely changing its value, or the address that it points to.
191 If we cannot change the value of the pointer, the address it points to, what's the use of the pointer?
192
193 "const pointer in true-sense of const as with cptr" is rarely used in C++ programming. For such purpose,
194 we can use reference. As I said in my previous videos, "all references" are constant, which means
195 once intialized at definition, it can never change the object that it references to.
196
197 So, when we say "const pointer," we usually do not mean "const pointer in true-sense of const as with cptr,"
198 but we rather mean the pointer that points to an object, through this pointer we do not want to modify
199 the value of the object that it points to.
200 */
201
202}
203
205{
206 MyClass obj; // this is a stack oriented object.
207 // it gets destroyed as soon as this block or scope ends.
208 // so we cannot return this stack based object as reference.
209
210 // dynamically allocated memory outlives this function block.
211 // so, we can safely return this object as reference.
212 MyClass *ptr = new MyClass;
213
214 return *ptr;
215}
216
218{
220
221 std::cout << "Okay, I caught a referenced!!" << std::endl;
222
223 // destory the memory in the free-store, or is called "heap memory."
224 delete &ref;
225}
226
228{
229 return &object; // legal, because object is a reference,
230 // this object will not get destoried at the end of this function block.
231}
232
234{
235 return *ptr; // legal, because ptr outlives this function block.
236}
237
239{
240 return rvalue; // legal, but not desirable.
241}
242
243MyClass& legal_but_dangerous(const MyClass& const_lvalue_ref)
244{
245 // this is possible, but highly dangerous.
246 return const_cast<MyClass&>(const_lvalue_ref);
247}
248
249int main()
250{
251 // test_which_member_function_gets_called();
252
253 //test_pointer_that_points_to_const_object();
254
256}
auto nl
reference_wrapper< Type > ref(Type &val) noexcept
auto & cout
auto & endl
const int & get_data() const
int & get_data()
int get_data(int offset) const
MyClass()=default
void test_which_member_function_gets_called()
MyClass & legal_but_dangerous(const MyClass &const_lvalue_ref)
MyClass & legal_return_value_again(MyClass *ptr)
#define FUNCTION_NAME
MyClass & legal_but_suspicious(MyClass &&rvalue)
void test_pointer_that_points_to_const_object()
MyClass * legal_return_value(MyClass &object)
void test_get_a_reference()
int main()
MyClass & get_a_reference()
constexpr new_line nl()
Definition: tpf_output.hpp:837
Stream output operators << are implemented.
Type functions are implemented.
#define Tpf_GetTypeCategory(instance_arg)
A macro that returns instance_arg's type category string name.
Definition: tpf_types.hpp:1428