Classes
Interfaces
Members
Type Members
Type members can hide some implementation details about a class.
We can alternatively use a type alias:
mutable
Members
If we want to make some exceptions to the const
requirements of member functions, we can mark some members as mutable
and its value can be changed by functions labeled with const
.
Initializers for Data Members of Class Type
Two forms of in-class initialization: =
or inside braces.
Note that the syntax { Screen(24, 80, '') }
is a form of list initialization, introduced in C++11. List initialization allows you to initialize containers like std::vector, arrays, or objects with a set of values.
Member Functions
::
Scope Operator
Using scope operator means that we are defining the function inside the scope of the class.
Member Functions and Non-member Functions
Member functions are used to fetch members from the class.
const
Member Functions
this
is of type Type *const
, which means that we cannot bind this
to a non-const function. We can specify const
after the parameter list to indicate that this
is a pointer to const
.
If the member was declared as a const
member function, then the definition must also specify const
after the parameter list.
Overloading Member Functions
We define two get()
functions in the Screen
class:
The compiler will define which function to call based on the arguments:
Functions That Return this
Functions that return a reference are lvalues, which means that they return the object itself, not a copy of the object.
Consider the following expression:
If the return values of the two methods are not references, the set
will take effect on a temporary copy that is returned by move
, rather than myScreen
.
Overloading Based on const
A const
member function that returns *this
as a reference should have a return type that is a reference to const
. We can overload a member function based on whether it is const
.
Constructors
Default Constructor
The compiler generates the default constructor for us if and only if we do not define any other constructor for the class.
ClassName() = default
: explictly instruct the compiler to generate a default constructor even if some other constructors are defined.
When a member is omitted from the constructor initializer list, it is implicitly initialized using the same process as is used by the synthesized default constructor.
A constructor that supplies default arguments for all its parameters also defines the default constructor.
In order to define an object that uses the default constructor for initialization:
Initializer List Constructor
You can initialize a vector using an initializer list in C++ as follows:
Both of these examples use the initializer list constructor. This constructor is defined as:
In this definition, the constructor accepts a parameter of type std::initializer_list<T>
.
The Difference between Initialization and Assignment
If a member is not explicitly initialized in the constructor initializer list, it will be default-initialized before the constructor body begins executing. However, const
members, reference members, and members without a default constructor should be explicitly initialized in the initializer list rather than being assigned after initialization.
Delegating Constructors
Implicit Class-Type Conversions
In scenarios where a function f
has a parameter of type T
that can be initialized with a single argument a
, you can directly pass a
to f
. This works because a constructor that takes a single argument enables an implicit conversion from the argument type to the class type.
Only One Class-Type Conversion Is Allowed: The following code will cause an error because it requires two implicit conversions:
To prevent a constructor from being used in situations where an implicit conversion would be required, you can declare the constructor as explicit
. The explicit
keyword is only applicable to constructors that can be called with a single argument.
Direct Initialization:
std::string s("Hello.\n")
Copy Initialization:
std::string s = "Hello.\n"
When a constructor is marked as
explicit
, the class cannot be initialized using string literal to perform copy initialization.
Moreover explicit
can also be used on conversion operators:
Order of Member Initialization
Members are initialized in the order in which they appear in the class definition. It is a good idea to write constructor initializers in the same order as the members are declared. Moreover, when possible, avoid using members to initialize other members.
Feature
new/delete
malloc/free
Memory Allocation
Allocates memory and calls constructor
Allocates memory only
Deallocation
Deallocates memory and calls destructor
Deallocates memory only
Type Safety
Type-safe, returns a pointer of the specified type
Not type-safe, returns void*
Initialization
Calls constructor, can initialize objects
No initialization
Overloading
Can be overloaded
Cannot be overloaded
Error Handling
Throws std::bad_alloc
on failure
Returns NULL
on failure
Placement
Supports placement new
Does not support placement allocation
Alignment
Handles alignment automatically
Requires manual alignment management
If a class needs a destructor, it also needs a copy constructor and an assignment operator. The “Rule of Three” thus helps avoid common pitfalls related to resource management in C++, ensuring that objects manage their resources correctly when they are copied, assigned, or destroyed.
Access Control and Encapsulation
We can define a class type using either class
or struct
. The only difference between using class
and using struct
to define a class is the default access level.
If we use the
struct
keyword, the members defined before the first access specifier are public.If we use
class
, then the members are private.
Friends
Access the nonpublic members by making another class or function a friend.
Now we can define the function outside the scope of SalesData
by:
We can even make a member function a friend:
Friend Declarations and Scope
The friend
function is not visible outside the class even if we have defined it inside the class.
In order to get this work, you can define g
inside the class body or define f
outside of the class.
Class Scope
Because the return type appears before the name of the class is seen, it appears ouÒtside the scope of class WindowManager
. To use ScreenIndex
for the return type, we must specify the class in which that type is defined.
Name Lookup and Class Scope
Name Lookup Steps
Check for the name within the same block, considering only declarations before its use.
If not found, search the enclosing scope(s).
If still not found, it results in a program error.
Class Declarations and Member Functions
All declarations are processed before definitions. Therefore, define any types or other entities used in function signatures before declaring the functions themselves.
Normal Block-Scope Name Lookup inside Member Definitions
Inside the member function.
Inside the class.
In scope before the member function definition.
Last updated