[toc]

class

  • The fundamental ideas behind classes are data abstraction and encapsulation.
  • The only difference between classes and structs is the default visibility.
  • Use the prefix m_ to denote a private variable.
  • class can reduces duplication

e.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#define LOG(x) std::cout << x << std::endl


class Player
{
public:
int x, y;
int speed;
void Move(int xa, int ya) //Functions in a class are called methods.
{
x += xa * speed;
y += ya * speed;
}

}; //Notice the semicolons



int main()
{
Player player1;
player1.x = 5;
player1.y = 5;
player1.speed= 5;

player1.Move(1, -1);
LOG(player1.x);
LOG(player1.y);
std::cin.get();

}

Initializing a class

1
2
3
4
5
Entity e("Randolfluo");		//stack
e.GetNum();
Entity* entity = new Entity("Randolfluo"); //heap
entity->GetNum();
delete entity ;

Allocate on the heap:

  • Object really really binggggg!
  • I want to explicitly control the lifetime of the object.

Inheritance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#define LOG(x) std::cout << x << std::endl

class Entity
{
public:
int x, y;

void Move(int xa, int ya)
{
x += xa;
y += ya;
}

};

class Player : public Entity //Anything that is not private in the Entity class is accessible to the player class
{
public:
const char* Name;

};

int main()
{
Player player1;
player1.x = 5;
player1.y = 5;
player1.Name = "Randolfluo";


player1.Move(1, -1);
LOG(sizeof Entity);
LOG(sizeof Player);
LOG(player1.Name);
LOG(player1.x);
LOG(player1.y);
std::cin.get();

}

Log class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>


class Log
{
public:
enum Level
{
LevelError = 0, LevelWarning, LevelInfo //LevelError = 0, LevelWarning = 1, LevelInfo = 2
}; //Only these three modes can be selected


private:
int m_LogLevel = LevelInfo;
public:
void SetLevel(int level)
{
m_LogLevel = level;
}
void Error(const char* message)
{
if (m_LogLevel >= LevelError)
std::cout << "[ERROR]: " << message << std::endl;
}
void Warn(const char* message)
{
if (m_LogLevel >= LevelWarning)
std::cout << "[WARNING]: " << message << std::endl;
}
void Info(const char* message)
{
if (m_LogLevel >= LevelInfo)
std::cout << "[INFO]: " << message << std::endl;
}
};



int main() {
Log log;
log.SetLevel(Log::LevelError);
log.Warn("Hello!");
log.Error("Hello!");
log.Info("hello!");
std::cin.get();
}

class lifetime

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <string>

class Entity
{
public:
Entity()
{
std::cout << "call Entity()" << std::endl;
}

~Entity()
{
std::cout << "destruct Entity()" << std::endl;
}
};

class ScopedPtr //ScopedPtr
{
private:
Entity* m_Ptr;
public:
ScopedPtr(Entity* ptr)
:m_Ptr(ptr)
{
}
~ScopedPtr()
{
delete m_Ptr;
}
};


int main(){
{
ScopedPtr e = new Entity(); //new Entity instead of ScopedPtr
//So e will be deleted after this scope
}
std::cin.get();
}
//output
//call Entity()
//destruct Entity()

constructor && destructor

  • Don’t forget initialization.

  • The constructor is automatically executed when the object is instantiated and does not need to be called manually.

  • A class can have multiple constructors. Each constructor must differ from the others in the number or types of its parameters.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>

class Entity
{
public:
float X, Y;
Entity() //no-args constructor
{
X = 0.0f;
Y = 0.0f;
}
Entity(float a, float b) //2-args constructor
{
X = a, Y = b;
}
// Entity() = delete; delete the default constructor

~Entity() //destructor
{
std::cout << "destroyed Entity!" << std::endl;
}


void Print() {
std::cout << X << ", " << Y << std::endl;
}
};


void Function()
{
Entity e;
Entity e1(10.0, 22.0);
e.Print();
e1.Print();


}


int main()
{
Function();
std::cin.get();
}

virtual function

  • Base on Dynamic Dispatch && v table,cause performance loss.
  • Like java’s overwrite
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <string>
class Entity
{
public:
virtual std::string GetName() { return "Entity"; } //virtual

};

class Player : public Entity
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name) {} //constructor initialize list

std::string GetName() override { return m_Name; } //override

};

void PrintName(Entity* entity)
{
std::cout << entity->GetName() << std::endl;
}


int main()
{
Entity* e = new Entity();
Player* p = new Player("Randolfluo");
PrintName(e);
PrintName(p);
std::cin.get();
}

virtual destruction

  • When the parent class pointer points to the child class, the correct fictitious function is called to prevent memory leaks
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<iostream>
#define print(x) std::cout<< x << std::endl

class Father1
{

public:
Father1() { print("Father1 Construction"); }
~Father1() { print("Father1 Destruction"); } //Causing a memory leak

};

class Father2
{

public:
Father2() { print("Father2 Construction"); }
virtual ~Father2() { print("Father2 Destruction"); } //virtual destruction

};

class Son1 :public Father1
{
private:
int* m_arr;
public:
Son1() { m_arr = new int[10]; print("Son1 Construction"); }
~Son1() { delete[] m_arr; print("Son1 Destruction"); }
};

class Son2 :public Father2
{
private:
int* m_arr;
public:
Son2() { m_arr = new int[10]; print("Son2 Construction"); }
~Son2() { delete[] m_arr; print("Son2 Destruction"); }
};


int main()
{
Father1* f1 = new Son1();
delete f1;
print("---------------------------------------------------------------");
Father2* f2 = new Son2();
delete f2;

std::cin.get();
}
//Father1 Construction
//Son1 Construction
//Father1 Destruction
//---------------------------------------------------------------
//Father2 Construction
//Son2 Construction
//Son2 Destruction
//Father2 Destruction

//TODO

Initialization List

  • Initializers help you get initialization done quickly
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <string>


class Entity2
{
public:
Entity2()
{
std::cout << "call Entity()" << std::endl;
}
Entity2(int x)
{
std::cout << "call Entity2() with arg " << x << std::endl;
}
};


class Entity
{
private:
std::string m_Name;
int x;
Entity2 entity22;
public:

Entity()
: m_Name("Unknown"), x(114514), entity22(2) //Initialization List
{
}
Entity(const std::string& name)
:m_Name(name),x(123) //Initialization List
{
}
const std::string& GetName() const { return m_Name; }

};

int main(){
Entity e;
Entity e1("Randolfluo");
std::cout << e.GetName() << std::endl;
std::cout << e.GetName() << std::endl;
std::cin.get();

}
output:
// call Entity2() with arg 2
// call Entity()
// Unknown
// Unknown

->

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <string>

struct Vector3
{
double x, y, z;
};

int main() {
int offset = (int)&((Vector3*)0)->z; //0+16
std::cout << offset << std::endl; //16
offset = (int)&((Vector3*)1000)->z; //1000+16
std::cout << offset << std::endl; //1016
std::cin.get();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <string>
class Entity
{
private:
int x;
public:
void Print() const { std::cout << "hello" << std::endl; }

};

class ScopedPtr
{
private:
Entity* m_obj;
public:
ScopedPtr(Entity* entity)
:m_obj(entity)
{
}

~ScopedPtr()
{
delete m_obj;
}
Entity* operator->() //overload ->
{
return m_obj;
}
const Entity* operator->() const
{
return m_obj;
}

};



int main() {

ScopedPtr e = new Entity;
e->Print(); //different class

std::cin.get();
}