Skip to content

Latest commit

 

History

History
1829 lines (1558 loc) · 30.2 KB

File metadata and controls

1829 lines (1558 loc) · 30.2 KB

Name Mangling

C++ supports function overloading, i.e., there can be more than one function with the same name but, different parameters. How does the C++ compiler distinguish between different functions when it generates object code – it changes names by adding information about arguments. This technique of adding additional information to function names is called Name Mangling.

Linkage Error in C++

int foo(int);

int main() 
{
	int x = 6;
	auto y = foo(x);
	std::cout << "y = " << y << '/n';
}

Error LNK2019 unresolved external symbol "int __cdecl foo(int)" (? foo@@YAHH@Z) The compiler can compile this code without errors because it sees the declaration of foo(int) and assumes you will link the definition of foo(int) provided elsewhere. However, during the linking phase, the linker cannot find a definition for foo(int), resulting in a linkage error.

Conditional Compiling

#ifdef __cplusplus
int foo(int);
#endif

int main() {
	auto x = foo(3);
}
#ifdef __cplusplus
	extern "C" {
#endif

	int f1(int);
	int f2(int);
	int f3(int);
	int f4(int);
	int f5(int);

#ifdef __cplusplus
	}
#endif

Function Deletion

Example :

int foo(int) = delete;

int main()
{
	foo(3);		// error : attempting to reference a deleted function
}

It is a compile-time operation that tells the compiler there is a function that returns int and takes one int parameter but calling this function causes syntax error.

Example :

int foo2(int) = delete;
int foo2(unsigned);

int main()
{
	foo2(2.5);		// ambiguity
}

Example :

int foo(float) = delete;
int foo(double) = delete;
int foo(long double) = delete;
int foo(int);

int main()
{
	foo(2.3);	// Error	C2280	'int foo(double)': attempting to reference a deleted function

}

Example :

int foo(int);

int main()
{
	foo(2.3);	// legal but there will be narrowing conversion
}

Example :

class Nec {
public:
	void func(int) = delete;
	void func(double);
};

int main()
{
	Nec mynec;
	mynec.func(23.45);	// valid
	mynec.func(23);		// invalid
}

Constructors

  • The primary purpose of a constructor is to initialize objects of a class. This initialization may involve setting initial values for member variables, allocating resources, or setting up any other state necessary for the newly created object to be used.

Example :

class Fighter {

private:
	std::string m_name;	// Constructors initialize the non-static member variables of a class
	int m_age;
	int m_power;
	//
};
  • The Constructor of a class must have the same name as the class.

  • The Constructor is a function that has no 'concept' of return value.

Example :

class Eni {
public:
	void Eni(int);		// syntax error because ctor has no concept of return value
};
  • The Constructor cannot be a free function (global function).
  • The Constructor cannot be a static member function or const member function.
  • 'this' can be used in its definition.
  • Can be public, private, protected.

Example :

class Eni2 {
private:
	Eni2(int);
};

int main() {
	Eni2 myeni(4);	// cannot access private member declared in class Eni2
}
  • Constructor can be overloaded.

Example :

// The constructor has 5 overloads.
class ex_class_2 {
private:
	ex_class_2();
	ex_class_2(int);
	ex_class_2(double);
	ex_class_2(int,int);
	ex_class_2(int,int,int);
};
  • Cannot be called using . or -> operators

Example :

class ex_class_12 {
public:
	ex_class_12();
	ex_class_12(int x);
	void foo();
};

int main()
{
	ex_class_12 myclass;
	myclass.foo();			// ok
	myclass.ex_class_12(12);	// error, cannot call ctor with . operator
}

Example :

class ex_class_1 {
private:
	ex_class_1(int);

	void func()
	{
		ex_class_1 ex_class(12);	// valid
	}
};

Default Constructor

A default constructor is a constructor that can be called with no arguments or every parameter has a default value.

Examples of Default Constructors :

class ex_class_3 {
private:
	ex_class_3();	  // defalt constructor
};
class ex_class_4 {
private:
	ex_class_4(int x);	// not a defalt constructor
};
class ex_class_5 {
private:
	ex_class_5(int x = 10);	// defalt constructor
};

Example :

// example.h
class ex_class_9 {
private:
	ex_class_9(int);		// constructor declaration
};

// example.cpp
// #include <example.h>
ex_class_9::ex_class_9(int x)		// constructor definition
{
	//..
}

Example :

// example.h
class ex_class_9 {
private:
	ex_class_9(int);		          // constructor declaration
};

// example.cpp
// #include <example.h>
ex_class_9::ex_class_9(int x)		// constructor definition
{
	//..
}

Special Member Functions

The codes of these functions (when certain conditions are met) can be written by the compiler.

  • default ctor
  • destructor
  • copy ctor
  • move ctor C++11
  • copy assignment
  • move assignment C++11

Revision on ODR

Example 1 :

// example.h
class ex_class_7 {
private:
	void func(int x);
};

void ex_class_7::func(int)
{
	//
}

If i include this header in 2 files, ODR is violated.

Example 2 :

// example.h
class ex_class_6 {
private:
	void func(int x)
	{
		//
	}
};

If i include this header in 10 files, ODR is not violated.

Example 3 :

// example.h
class ex_class_8 {
private:
	inline void func(int x);
};

void ex_class_8::func(int)	// or inline void ex_class_8::func(int)
{
	//
}

If i include this header in 2 files, ODR is not violated

Destructor

  • Used to end the life of the object of a class.
  • The Destructor is a non-static member function.
  • The Destructor of a class must have the same name as the class but ~ is put in front of the function.

Example :

class ex_class_10 {
private:
	ex_class_10(int x);	// constructor
	~ex_class_10();		// destructor
};
  • The Destructor is a function that has no 'concept' of return value.
  • The Destructor cannot be a free function (global function).
  • The Destructor cannot be a static member function or const member function.
  • 'this' can be used in its definition.
  • Can be public, private, protected.
  • Destructor CANNOT be overloaded.
  • Destructor must have a 'void' parameter list
  • Destructor can be called using . or -> operators

Example :

class ex_class_12 {
public:
	ex_class_12();
	ex_class_12(int x);
	void foo();
};

int main()
{
	ex_class_12 myclass;
	myclass.foo();	// ok
	myclass.ex_class_12(12);	// error, cannot call ctor with . operator
	myclass.~ex_class_12();		// ok, can call dtor with . operator but it is not very common 
}

Storage Classes

  • static storage class
  • automatic storage class
  • dynamic storage class
  • thread-local storage class

The following classes have static life-span:

  • global variables
  • static local variables
  • static data members of a class

Example :

class ex_class_13{
public:
	ex_class_13()
	{
		std::cout << "ex_class_13() this = " << this << '\n';
	}

	~ex_class_13()
	{
		std::cout << "ex_class_13 destructor this = " << this << '\n';
	}
};

ex_class_13 gex_class;

int main()
{
	std::cout << "main starting\n";
	std::cout << "&gex_class = " << &gex_class << "\n";
	std::cout << "main continuing\n";
	std::cout << "main ending\n";
}

Output:

ex_class_13() this = 00007FF6267A1180
main starting
&gex_class = 00007FF6267A1180
main continuing
main ending
ex_class_13 destructor this = 00007FF6267A1180

Example :

class ex_class_14 {
public:
	ex_class_14()
	{
		std::cout << "ex_class_14() this = " << this << '\n';
	}

	~ex_class_14()
	{
		std::cout << "ex_class_14 destructor this = " << this << '\n';
	}
	void foo()
	{
		//..
	}

	void bar()
	{
		//..
	}

int main()
{
	std::cout << &ex_class_14::foo << '\n';		// these functions also have an address in memory
	std::cout << &ex_class_14::bar << '\n';
}

When a class has multiple constructors, the specific constructor called during object creation depends on the arguments provided when the object is instantiated.

Example :

class ex_class_15 {
public:
	ex_class_15()
	{
		std::cout << "ex_class_15() this = " << this << '\n';
	}

	ex_class_15(int)
	{
		std::cout << "ex_class_15(int) this = " << this << '\n';
	}

	~ex_class_15()
	{
		std::cout << "ex_class_15 destructor this = " << this << '\n';
	}
};

ex_class_15 gex_class;

int main()
{
	std::cout << "main starting\n";
	std::cout << "&gex_class = " << &gex_class << "\n";
	std::cout << "main continuing\n";
	std::cout << "main ending\n";
}

Output:

ex_class_15() this = 00007FF792701200
main starting
&gex_class = 00007FF792701200
main continuing
main ending
ex_class_15 destructor this = 00007FF792701200

Example :

class ex_class_16 {
public:
	ex_class_16()
	{
		std::cout << "ex_class_16() this = " << this << '\n';
	}

	ex_class_16(int)
	{
		std::cout << "ex_class_16(int) this = " << this << '\n';
	}

	~ex_class_16()
	{
		std::cout << "ex_class_16 destructor this = " << this << '\n';
	}
};

ex_class_16 gex_class(5);

int main()
{
	std::cout << "main starting\n";
	std::cout << "&gex_class = " << &gex_class << "\n";
	std::cout << "main continuing\n";
	std::cout << "main ending\n";
}

Output:

ex_class_16(int) this = 00007FF6BFC11200
main starting
&gex_class = 00007FF6BFC11200
main continuing
main ending
ex_class_16 destructor this = 00007FF6BFC11200

Example :

class ex_class_17 {
public:
	ex_class_17()
	{
		std::cout << "ex_class_17() this = " << this << '\n';
	}

	~ex_class_17()
	{
		std::cout << "ex_class_17 destructor this = " << this << '\n';
	}
};

void foo()
{
	static ex_class_17 x;

}

int main()
{
	std::cout << "main starting\n";
	foo();
	std::cout << "main ending\n";
}

Output:

main starting
ex_class_17() this = 00007FF7746D0200
main ending
ex_class_17 destructor this = 00007FF7746D0200

Example :

class ex_class_18 {
public:
	ex_class_18()
	{
		std::cout << "ex_class_18() this = " << this << '\n';
	}

	~ex_class_18()
	{
		std::cout << "ex_class_18 destructor this = " << this << '\n';
	}
};

void foo()
{
	std::cout << "foo called\n";
	static ex_class_18 x;
}

int main()
{
	std::cout << "main starting\n";
	foo();		// constructor is called only once
	foo();
	foo();
	foo();
	foo();
	std::cout << "main ending\n";
}

Output:

main starting
foo called
ex_class_18() this = 00007FF65B530200
foo called
foo called
foo called
foo called
main ending
ex_class_18 destructor this = 00007FF65B530200

Example :

class ex_class_19 {
public:
	ex_class_19()
	{
		std::cout << "ex_class_19() this = " << this << '\n';
	}

	~ex_class_19()
	{
		std::cout << "ex_class_19 destructor this = " << this << '\n';
	}
	char buf[256]{};
};

ex_class_19 ar[16];

int main()
{
	std::cout << "main starting\n";
	std::cout << "main ending\n";
}

Output:

ex_class_19() this = 00007FF6660C1200
ex_class_19() this = 00007FF6660C1300
ex_class_19() this = 00007FF6660C1400
ex_class_19() this = 00007FF6660C1500
ex_class_19() this = 00007FF6660C1600
ex_class_19() this = 00007FF6660C1700
ex_class_19() this = 00007FF6660C1800
ex_class_19() this = 00007FF6660C1900
ex_class_19() this = 00007FF6660C1A00
ex_class_19() this = 00007FF6660C1B00
ex_class_19() this = 00007FF6660C1C00
ex_class_19() this = 00007FF6660C1D00
ex_class_19() this = 00007FF6660C1E00
ex_class_19() this = 00007FF6660C1F00
ex_class_19() this = 00007FF6660C2000
ex_class_19() this = 00007FF6660C2100
main starting
main ending
ex_class_19 destructor this = 00007FF6660C2100
ex_class_19 destructor this = 00007FF6660C2000
ex_class_19 destructor this = 00007FF6660C1F00
ex_class_19 destructor this = 00007FF6660C1E00
ex_class_19 destructor this = 00007FF6660C1D00
ex_class_19 destructor this = 00007FF6660C1C00
ex_class_19 destructor this = 00007FF6660C1B00
ex_class_19 destructor this = 00007FF6660C1A00
ex_class_19 destructor this = 00007FF6660C1900
ex_class_19 destructor this = 00007FF6660C1800
ex_class_19 destructor this = 00007FF6660C1700
ex_class_19 destructor this = 00007FF6660C1600
ex_class_19 destructor this = 00007FF6660C1500
ex_class_19 destructor this = 00007FF6660C1400
ex_class_19 destructor this = 00007FF6660C1300
ex_class_19 destructor this = 00007FF6660C1200

Example :

class ex_class_20{
public:
	ex_class_20()
	{
		std::cout << "ex_class_20() this = " << this << '\n';
	}

	~ex_class_20()
	{
		std::cout << "ex_class_20 destructor this = " << this << '\n';
	}
	char buf[256]{};
};

void foo()
{
	ex_class_20 x;
}		// because x  is automatic storage class, the life of the object ends here so destructor is called

int main()
{
	std::cout << "main starting\n";
	foo();
	std::cout << "main ending\n";
}

Output:

main starting
ex_class_20() this = 0000001DC90FF6B0
ex_class_20 destructor this = 0000001DC90FF6B0
main ending

Example :

class ex_class_21 {
public:
	ex_class_21()
	{
		std::cout << "ex_class_21() this = " << this << '\n';
	}

	~ex_class_21()
	{
		std::cout << "ex_class_21 destructor this = " << this << '\n';
	}
	char buf[256]{};
};

void foo()
{
	ex_class_21 x;
}		// because x  is automatic storage class, the life of the object ends here so destructor is called

int main()
{
	std::cout << "main starting\n";
	foo();
	foo();
	foo();
	std::cout << "main ending\n";
}

Output:

main starting
ex_class_21() this = 000000B26155F6A0
ex_class_21 destructor this = 000000B26155F6A0
ex_class_21() this = 000000B26155F6A0
ex_class_21 destructor this = 000000B26155F6A0
ex_class_21() this = 000000B26155F6A0
ex_class_21 destructor this = 000000B26155F6A0
main ending

Example :

class ex_class_22 {
public:
	ex_class_22()
	{
		std::cout << "ex_class_22() this = " << this << '\n';
	}

	~ex_class_22()
	{
		std::cout << "ex_class_22 destructor this = " << this << '\n';
	}
};

int main()
{
	std::cout << "main starting\n";
	for (int i = 0; i < 10; ++i)
	{	
		ex_class_22 myclass;	// ctor and dtor will be called 10 times
	}
	std::cout << "main ending\n";
}

Output:

main starting
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
ex_class_22() this = 000000F1045BF934
ex_class_22 destructor this = 000000F1045BF934
main ending

Example :

class ex_class_23 {
public:
	ex_class_23()
	{
		std::cout << "ex_class_23() this = " << this << '\n';
	}

	~ex_class_23()
	{
		std::cout << "ex_class_23 destructor this = " << this << '\n';
	}
};

int main()
{
	std::cout << "main starting\n";
	for (int i = 0; i < 10; ++i)
	{
		std::cout << "i = " << i << '\n';

		static ex_class_23 myclass;		// ctor and dtor will be called once
	}
	std::cout << "main ending\n";
}

Output:

main starting
i = 0
ex_class_23() this = 00007FF6A16C0200
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
main ending
ex_class_23 destructor this = 00007FF6A16C0200

Example :

class ex_class_24 {
public:
	ex_class_24()
	{
		std::cout << "ex_class_24() this = " << this << '\n';
	}

	~ex_class_24()
	{
		std::cout << "ex_class_24 destructor this = " << this << '\n';
	}
};

int main()
{
	ex_class_24 myclass;		// constructor called only once
	ex_class_24* ptr = &myclass;
}

Output:

ex_class_24() this = 0000005C64CFF9B4
ex_class_24 destructor this = 0000005C64CFF9B4

Example :

class ex_class_25 {
public:
	ex_class_25()
	{
		std::cout << "ex_class_25() this = " << this << '\n';
	}

	~ex_class_25()
	{
		std::cout << "ex_class_25 destructor this = " << this << '\n';
	}
};

int main()
{
	ex_class_25 myclass;		// only one object created
	ex_class_25& r1 = myclass;	// this doesn't create an object
	ex_class_25& r2 = myclass;
	ex_class_25& r3 = myclass;
	ex_class_25& r4 = myclass;
}

Output:

ex_class_25() this = 00000037DBEFF804
ex_class_25 destructor this = 00000037DBEFF804

Example: Print numbers from 1 to 100 without using loops.

class ex_class_26 {
public:
	ex_class_26()
	{
		static int x = 0;
		std::cout << "x = " << ++x << '\n';
	}
};

int main()
{
	ex_class_26 arr[100];	// creates 100 objects of ex_class_26 class
}

Output:

x = 1
x = 2
x = 3
x = 4
x = 5
x = 6
x = 7
x = 8
x = 9
x = 10
x = 11
x = 12
...
x = 94
x = 95
x = 96
x = 97
x = 98
x = 99
x = 100

Example :

class Logger {
public:
	Logger()
	{
		mf = std::fopen("logger.txt", "w");
		///...
	}
	~Logger()
	{
		fclose(mf);
	}
	void foo()
	{
		std::fprintf(mf, "foo called\n");
	}

	void bar()
	{
		std::fprintf(mf, "bar called\n");
	}
private:
	FILE* mf;
};

void foo()
{
	Logger lg;	// file opens when the object is created

	lg.foo();
	lg.bar();
}				// life of object finishes here

int main()
{
	foo();
	// at this point, file is closed
}

Example :

struct ex_class_27 {
	ex_class_27()
	{
		std::cout << "default ctor\n";
	}

	void print()const
	{
		std::cout << "mx = " << mx << "\n";
	}
	int mx;
};

int main()
{
	ex_class_27 myclass1;	// default initialization
	// default ctor is called for default initialized objects


	ex_class_27 myclass2{};	// value initialization
	// default ctor is called for value initialized objects

	
	myclass1.print();		// undefined behavior because mx has garbage value
	myclass2.print();		// zero-initialized, no undefined behavior here, mx = 0

}

Example :

struct ex_class_28 {
	void print()const
	{
		std::cout << "mx = " << mx << "\n";
	}
	int mx;
};

ex_class_28 myclass;		// default initialization
				// no undefined-behavior because the object has static life-span
				//! static objects, before initialization, get zero-initialized
int main()
{
	myclass.print();
}

Example :

struct ex_class_29 {
public:
	ex_class_29(int x)
	{
		std::cout << "ex_class_29(int x) x = " << x << "this = " << this << "\n";
	}
};

int main()
{
	ex_class_29 class1(45);		// direct initialization
	std::cout << "&class1 = " << &class1 << '\n';	// class1 and this have same address
}

Example :

struct ex_class_30 {
public:
	ex_class_30(int x)
	{
		std::cout << "ex_class_30(int x) x = " << x << "this = " << this << "\n";
	}
};

int main()
{
	ex_class_30 class1{67};		// direct list initialization
	std::cout << "&class1 = " << &class1 << '\n';
}

Example :

struct ex_class_31 {
public:
	ex_class_31(int x)
	{
		std::cout << "ex_class_31(int x) x = " << x << "this = " << this << "\n";
	}
};

int main()
{
	ex_class_31 class1 = 10;	// copy initialization
}

Example :

struct ex_class_32 {
public:
	ex_class_32()
	{
		std::cout << "ex_class_32 this = " << this << "\n";
	}

	ex_class_32(int x)
	{
		std::cout << "ex_class_32(int x) x = " << x << "this = " << this << "\n";
	}
};

int main()
{
	ex_class_32 class1;		// default initialization
	ex_class_32 class2{};		// value initialization
	ex_class_32 class3(12);		// direct initialization
	ex_class_32 class4{36};		// direct list initialization
	ex_class_32 class5 = 65;	// copy initialization
}

Example :

struct ex_class_33 {
public:
	ex_class_33()
	{
		std::cout << "ex_class_33 this = " << this << "\n";
	}

	ex_class_33(int x)
	{
		std::cout << "ex_class_33(int x) x = " << x << "this = " << this << "\n";
	}

	ex_class_33(double x)
	{
		std::cout << "ex_class_33(double x) x = " << x << "this = " << this << "\n";
	}

	ex_class_33(int x, int y)
	{
		std::cout << "ex_class_33(int x, int y) x = " << x << "y = " << y << "this = " << this << "\n";
	}
};

int main()
{
	ex_class_33 class1;		// default ctor called
	ex_class_33 class2(45);		// ex_class_33(int x) called
	ex_class_33 class3(4.5f);	// ex_class_33(double x) called
	ex_class_33 class4(4.5L);	// syntax error, ambiguity
	
	ex_class_33 class5 = { 3,5 };	// ex_class_33(int x, int y) called
}

Example :

class ex_class_34{

public:
	~ex_class_34()
	{
		std::cout << "destructor\n";
	}
};

int main()
{
	ex_class_34 myclass;	// destructor gets called
				// what about constructor? :o
				// default constructor called which was written by compiler
}

Example :

class ex_class_35 {

public:
	ex_class_35() = default;		// i ask the compiler to write the constructor
	~ex_class_35()
	{
		std::cout << "destructor\n";
	}
};

int main()
{
	ex_class_35 myclass;
}

Example :

class ex_class_36 {

public:
	ex_class_36(int) {};

};

int main() {
	ex_class_36 myclass;	// syntax error : no appropriate default constructor available
}

Output:

syntax error : no appropriate default constructor available


Special Member Functions

Special member functions can be:

1. User Declared

- defined

class ex_class_37 {

public:
	ex_class_37();				// user declared defined

};

- defaulted

class ex_class_38 {

public:
	ex_class_38() = default;	// user declared defaulted
	// i am declaring it, but the compiler will define it
};

- deleted

class ex_class_39 {

public:
	ex_class_39() = delete;	// user declared
	// i am declaring it, but calling this function is a syntax error
};

2. implicitly declared

- defaulted

class ex_class_40 {
public:
	// this class has default constructor
	// has destructor
	// none is user declared
	// both are implicitly declared
};
class ex_class_41 {
public:
	// the compiler declares and defines constructor and destructor
	// implicitly declared defaulted
};

int main()
{
	ex_class_41 m;
}

- deleted

class ex_class_42 {

	const int x;

	// this class has default constructor, it is implicitly declared
};

int main()
{
	ex_class_42 m;		// syntax error, the default constructor cannon be referenced - it is a deleted function
	// implicitly declared deleted
}

Output:

syntax error, the default constructor cannon be referenced - it is a deleted function

3. not declared

struct ex_struct_1 {
	ex_struct_1(int);	// default constructor is NOT 'user declared'
	// default constructor is NOT 'implicitly declared'
	// default constructor is 'not declared'
};

int main()
{
	ex_struct_1 struct_1;	// error : no default constructor exists
}

Output:

error : no default constructor exists


Example :

class ex_class_43 {
public:
	ex_class_43()
	{
		mx = 0;		// assignment, not initialization
		my = 0;		// when the program enters the constructor block, member variables have already been initialized
	}

private:
	int mx, my;
};

Example :

class ex_class_44 {
public:
	ex_class_44()
	{

	}

private:
	int& r;			// syntax error, references do not get default initialized
				// references must be initialized

	const int x;	// const objects do not get default initialized
			// an object of const-qualified type must be initialized
};

Output:

syntax error, references do not get default initialized


Constructor (Member) Initializer List

This is a syntax that only constructors can use.

Example :

class ex_class_45 {
public:
	ex_class_45();		// constructor : user declared declaration
private:
	int mx;
	double my;
	//
};
ex_class_45::ex_class_45() : mx(5), my(7.5)		// valid syntax
{
	//
}
ex_class_45::ex_class_45() : mx{ 5 }, my{ 7.5 }
{
	// also valid syntax, but narrowing conversion will cause syntax error
}

Example :

In C++, const members must be initialized when an object is created. Since mx is not given a value in the constructor initializer list, the compiler will generate an error.

class ex_class_46 {
public:
	ex_class_46();
private:
	const int mx;
};

ex_class_46::ex_class_46()
{
	// syntax error : an object of const - qualified type must be initialized	
}

Output:

syntax error : an object of const - qualified type must be initialized


Example :

In C++, reference members must be initialized when an object is created. This is because references must always refer to an object; they cannot exist without being bound to an object. The constructor in ex_class_47 does not initialize the reference member r, leading to a compilation error.

class ex_class_47 {
public:
	ex_class_47();
private:
	int& r;
};

ex_class_47::ex_class_47()
{
	// syntax error : references do not get default initialized
}

Output:

syntax error : references do not get default initialized


What is the difference between these two? The two classes provided, ex_class_48 and ex_class_49, demonstrate two different methods of initializing member variables.

class ex_class_48 {
public:
	ex_class_48(int x) : mx(x) {}	// here mx is firstly default initialized, then assigned 
private:
	int mx;
};

In ex_class_48, the member variable mx is directly initialized using the constructor's member initializer list (: mx(x) {}). This is known as direct initialization.

class ex_class_49 {
public:
	ex_class_49(int x)
	{
		mx = x;
	}
private:
	int mx;
};

In ex_class_49, mx is default-initialized and then assigned a value within the constructor body. Since mx is of a primitive type (int), default initialization for this type when occurring inside a class means that mx will be uninitialized (holding an indeterminate value) before it gets assigned the value of x inside the constructor body.


Order of Initialization of Class Members

In C++, the order of initialization of class members is determined by the order of their declaration in the class, not by the order they are listed in the constructor's member initializer list.

Example :

class ex_class_50 {
public:
    ex_class_50(int a) : my(a), mx(my / 3) {}
    // undefined behavior because 'my' has not yet been initialized and holds an indeterminate value at the time 'mx' is being initialized
private:
    int mx, my; // first mx, then my
};

Example :

class ex_class_51 {
public:
	ex_class_51() :x(10) {}

	void print()const
	{
		std::cout << "x = " << x << '\n';
	}
private:
	int x;
};

int main()
{
	ex_class_51 ex;
	ex.print();

}

Output:

x = 10

Example :

class ex_class_52 {
public:
	ex_class_52() {}

	void print()const
	{
		std::cout << "x = " << x << '\n';	// undefined behavior
	}
private:
	int x;
};

int main()
{
	ex_class_52 ex;
	ex.print();

}

Example :

class ex_class_53 {
public:
	ex_class_53(int val) : x(val) {}

	void print()const
	{
		std::cout << "x = " << x << '\n';
	}
private:
	int x;
};

int main()
{
	ex_class_53 ex;	// syntax error, no default constructor exists for class ex_class_53
	ex.print();

}

Example :

class ex_class_54 {
public:
	ex_class_54(int val) : x(val) {}

	void print()const
	{
		std::cout << "x = " << x << '\n';
	}
private:
	int x;
};

int main()
{
	ex_class_54 ex(45);
	ex.print();
}

Output:

x = 45

Example :

The first x (after the colon) refers to the member variable of the class ex_class_55. The second x (inside the parentheses) refers to the parameter passed to the constructor. While this approach is syntactically correct and works as intended, it may lead to confusion for someone reading the code, especially in more complex classes or functions.

class ex_class_55 {
public:
	ex_class_55(int x) : x(x) {}
	// the first 'x' is searched in class scope
	// the 'x' inside the parantheses is searched as argument variable
	void print()const
	{
		std::cout << "x = " << x << '\n';
	}
private:
	int x;
};

int main()
{
	ex_class_55 ex(45);
	ex.print();
}

Output:

x = 45

Example :

class ex_class_56 {
public:
	ex_class_56() : x(x) {}		// 'x' is initialized with its own garbage value
	void print()const
	{
		std::cout << "x = " << x << '\n';
	}
private:
	int x;
};

Example :

class ex_class_57 {
public:
	ex_class_57(int x) : mx(x) {}
	void print()const
	{
		std::cout << "mx = " << mx << '\n';		// mx = 45
		std::cout << "my = " << my << '\n';		// garbage value
	}
private:
	int mx, my;
};

int main()
{
	ex_class_57 ex(45);
	ex.print();
}

Output:

mx = 45
my = -858993460 (garbage value)

Default Member Initializer

This feature provides a default value for a member that will be used unless an initializer is provided at the point of object creation or in the constructor's member initializer list.

Example :

class ex_class_58 {
public:

private:
	int mx = 0;		// this syntax came with modern C++ ( C++11 )
	// Default Member Initializer
	// or In-Class Initializer
};

Example :

class ex_class_59 {
public:
	ex_class_59()	// if i write the constructor like this, the compiler will put ' : mx(0) '
	{
	}
private:
	int mx = 0;
};

Example :

class ex_class_60 {
public:

	ex_class_60() : mx(45)	 // okay, default member initializer not used
	{

	}

	void print()const
	{
		std::cout << "mx = " << mx << '\n';
	}

private:
	int mx = 0;

};

int main()
{
	ex_class_60 ex;
	ex.print();
}

Output:

mx = 45

Example :

class ex_class_61 {
public:

	ex_class_61()
	{

	}

	void print()const
	{
		std::cout << "mx = " << mx << '\n';
	}

private:
	int mx{ 765 };	// legal
	//int mx( 765 );	// illegal
};

int main()
{
	ex_class_61 ex;
	ex.print();
}

Output:

mx = 765

Example :

class Point {
public:
	void print() const
	{
		std::cout << mx << " " << my << " " << mz << '\n';	// undefined behavior
	}

private:
	int mx, my, mz;
};

int main()
{
	Point mypoint;		// constructer is implicitly declared defaulted
	myclass.print();
}

Example :

class Point {
public:
	// the compiler writes: Point() : mx(0), my(0), mz(0) {}
	void print() const
	{
		std::cout << mx << " " << my << " " << mz << '\n';
	}

private:
	int mx = 0, my = 0, mz = 0;
};

int main()
{
	Point mypoint;		// constructer is implicitly declared defaulted
	myclass.print();
}

Output:

0 0 0

Example :

class Point {
public:
	
	Point() :mx(1), my(1), mz(1) {}
	
	void print() const
	{
		std::cout << mx << " " << my << " " << mz << '\n';
	}

private:
	int mx = 0, my = 0, mz = 0;
};

int main()
{
	Point mypoint;
	myclass.print();
}

Output:

1 1 1

Example :

class Point {
public:
	
	Point() :mx(1){}	// default member initializer used for my and mz
	
	void print() const
	{
		std::cout << mx << " " << my << " " << mz << '\n';
	}

private:
	int mx = 0, my = 0, mz = 0;
};

int main()
{
	Point mypoint;
	myclass.print();
}

Output:

1 0 0