1- Classes and Objects
Structures
- A struct in C is a type consisting of a sequence of data members
- Some functions/Statements are needed to operate the data members of an object of a struct type
不不小心操作错误,不小心越界
Classes
- You should be very careful to manipulated the data members in a struct object
- Can we improve struct to a better one ?
- Yes, it is
class
! We can put some member functions in it
cpp
class Student
{
private:
static size_t student_total; // declaration only
//inline static size_t student_total = 0; //C++17, definition outside isn't needed
char * name;
int born;
bool male;
void setName(const char * s)
{
strncpy(name, s, sizeof(name));
}
};
cpp
Student yu;
yu.setName("Yu");
firstclass.cpp
cpp
#include <iostream>
#include <cstring>
class Student
{
public:
char name[4];
int born;
bool male;
void setName(const char * s)
{
strncpy(name, s, sizeof(name));
}
void setBorn(int b)
{
born = b;
}
void setGender(bool isMale)
{
male = isMale;
}
void printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
};
int main()
{
Student yu;
yu.setName("Yu");
yu.setBorn(2000);
yu.setGender(true);
yu.born = 2001; // it can also be manipulated directly
yu.printInfo();
std::cout << "It's name is " << yu.name << std::endl;
return 0;
}
bash
Name: Yu
Born in 2001
Gender: Male
It's name is Yu
Access Specifiers
- You can protect data members by access specifier
private
- Then data member can only be accessed by well designed member functions
access_attribute.cpp
cpp
#include <iostream>
#include <cstring>
class Student
{
private:
char name[4];
int born;
bool male;
public:
void setName(const char * s)
{
strncpy(name, s, sizeof(name));
}
void setBorn(int b)
{
born = b;
}
void setGender(bool isMale)
{
male = isMale;
}
void printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
};
int main()
{
Student yu;
yu.setName("Yu");
yu.setBorn(2000);
yu.setGender(true);
yu.born = 2001; // you cannot access a private member
yu.printInfo();
return 0;
}
bash
access-attribute.cpp:37:8: error: 'born' is a private member of 'Student'
yu.born = 2001; // you cannot access a private member
^
access-attribute.cpp:8:9: note: declared private here
int born;
^
Member Functions
- A member function can be defined inside or outside class
- 如果在类内部实现函数则就是
inline
函数
function.cpp
cpp
#include <iostream>
#include <cstring>
class Student
{
private:
char name[4];
int born;
bool male;
public:
void setName(const char * s)
{
strncpy(name, s, sizeof(name));
}
void setBorn(int b)
{
born = b;
}
// the declarations, the definitions are out of the class
void setGender(bool isMale);
void printInfo();
};
void Student::setGender(bool isMale)
{
male = isMale;
}
void Student::printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
int main()
{
Student yu;
yu.setName("Yu");
yu.setBorn(2000);
yu.setGender(true);
yu.printInfo();
return 0;
}
bash
Name: Yu
Born in 2000
Gender: Male
File Structures
- The source code can be placed into multiple files
student.hpp
cpp
#pragma once
#include <cstring>
class Student
{
private:
char name[4];
int born;
bool male;
public:
void setName(const char * s)
{
strncpy(name, s, sizeof(name));
}
void setBorn(int b)
{
born = b;
}
// the declarations, the definitions are out of the class
void setGender(bool isMale);
void printInfo();
};
student.cpp
cpp
#include <iostream>
#include "student.hpp"
void Student::setGender(bool isMale)
{
male = isMale;
}
void Student::printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
如果include <>
从编译器路径查找,如果是include ""
从编译器和当前目录找
main.cpp
cpp
#include "student.hpp"
int main()
{
Student yu;
yu.setName("Yu");
yu.setBorn(2000);
yu.setGender(true);
yu.printInfo();
return 0;
}
CMakeList.txt
cpp
cmake_minimum_required(VERSION 3.12)
project(persondemo)
ADD_EXECUTABLE(persondemo main.cpp student.cpp)
bash
cd multi-files
mkdir build
cd build
cmake ..
make
./persondemo
bash
Name: Yu
Born in 2000
Gender: Male
2-Constructors and Destructors
Constructors
- Different from
struct
in C, a constructor will be invoked when creating an object of aclass
(1) struct
in C: allocate memory
(2) class
in C++: allocate memory & invoke a constructor
- But, No constructor is defined explicitly in previous examples
(1) the compiler wil generate one with empty body
如果没有人为定义构造函数,则自动会有一个空的构造函数
- The same name with the class
- Have no return value
cpp
class Student
{
private:
char name[4];
int born;
bool male;
public:
Student()
{
name[0] = 0;
born = 0;
male = false;
cout << "Constructor: Person()" << endl;
}
}
Student(const char * initName, int initBorn, bool isMale)
{
setName(initName);
born = initBorn;
male = isMale;
cout << "Constructor: Person(const char, int , bool)" << endl;
}
}
- The members can also be initialized as follows
cpp
Student(const char * initName): born(0), male(true)
{
setName(initName);
cout << "Constructor: Person(const char*)" << endl;
}
把成员变量born
初始化为0
, 把male
初始化为true
constructor.cpp
cpp
#include <iostream>
#include <cstring>
using namespace std;
class Student
{
private:
char name[4];
int born;
bool male;
public:
Student()
{
name[0] = 0;
born = 0;
male = false;
cout << "Constructor: Person()" << endl;
}
Student(const char * initName): born(0), male(true)
{
setName(initName);
cout << "Constructor: Person(const char*)" << endl;
}
Student(const char * initName, int initBorn, bool isMale)
{
setName(initName);
born = initBorn;
male = isMale;
cout << "Constructor: Person(const char, int , bool)" << endl;
}
void setName(const char * s)
{
strncpy(name, s, sizeof(name));
}
void setBorn(int b)
{
born = b;
}
// the declarations, the definitions are out of the class
void setGender(bool isMale);
void printInfo();
};
void Student::setGender(bool isMale)
{
male = isMale;
}
void Student::printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
int main()
{
Student yu;
yu.printInfo();
yu.setName("Yu");
yu.setBorn(2000);
yu.setGender(true);
yu.printInfo();
Student li("li");
li.printInfo();
Student xue = Student("XueQikun", 1962, true);
//a question: what will happen since "XueQikun" has 4+ characters?
xue.printInfo();
Student * zhou = new Student("Zhou", 1991, false);
zhou->printInfo();
delete zhou;
return 0;
}
bash
Constructor: Person()
Name:
Born in 0
Gender: Female
Name: Yu
Born in 2000
Gender: Male
Constructor: Person(const char*)
Name: li
Born in 0
Gender: Male
Constructor: Person(const char, int , bool)
Name: XueQ�
Born in 1962
Gender: Male
Constructor: Person(const char, int , bool)
Name: Zhou�
Born in 1991
Gender: Female
Destructors
- The destructor will be invoked when the object is destroyed
- Be formed from the class name preceded by a tilde(~)
- Have no return value, no parameters
cpp
~Student()
{
cout << "To destroy object: " << name << endl;
delete [] name;
}
析构函数只能有一个
析构函数常做的事情:释放内存,关闭文件,断掉网络etc
destructor.cpp
cpp
#include <iostream>
#include <cstring>
using namespace std;
class Student
{
private:
char * name;
int born;
bool male;
public:
Student()
{
name = new char[1024]{0};
born = 0;
male = false;
cout << "Constructor: Person()" << endl;
}
Student(const char * initName, int initBorn, bool isMale)
{
name = new char[1024];
setName(initName);
born = initBorn;
male = isMale;
cout << "Constructor: Person(const char, int , bool)" << endl;
}
~Student()
{
cout << "To destroy object: " << name << endl;
delete [] name;
}
void setName(const char * s)
{
strncpy(name, s, 1024);
}
void setBorn(int b)
{
born = b;
}
// the declarations, the definitions are out of the class
void setGender(bool isMale);
void printInfo();
};
void Student::setGender(bool isMale)
{
male = isMale;
}
void Student::printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
int main()
{
{
Student yu;
yu.printInfo();
yu.setName("Yu");
yu.setBorn(2000);
yu.setGender(true);
yu.printInfo();
}
Student xue = Student("XueQikun", 1962, true);
xue.printInfo();
Student * zhou = new Student("Zhou", 1991, false);
zhou->printInfo();
delete zhou;
return 0;
}
bash
g++ destructor.cpp --std=c++11
bash
Constructor: Person()
Name:
Born in 0
Gender: Female
Name: Yu
Born in 2000
Gender: Male
To destroy object: Yu
Constructor: Person(const char, int , bool)
Name: XueQikun
Born in 1962
Gender: Male
Constructor: Person(const char, int , bool)
Name: Zhou
Born in 1991
Gender: Female
To destroy object: Zhou
To destroy object: XueQikun
人工手动调用析构函数 delete zhou
,作用域结束跳出也会自动调用析构函数
如果对于new
的对象不进行手动删除delete
则作用域结束也不会动态调用析构函数,造成内存泄漏
cpp
Student * class1 = new Student[3]{
{"Tom", 2000, true},
{"Bob", 2001, true},
{"Amy", 2002, false},
};
- What is the different between the following two lines?
cpp
delete class1;
delete [] class1;
array.cpp
cpp
#include <iostream>
#include <cstring>
using namespace std;
class Student
{
private:
char * name;
int born;
bool male;
public:
Student()
{
name = new char[1024]{0};
born = 0;
male = false;
cout << "Constructor: Person()" << endl;
}
Student(const char * initName, int initBorn, bool isMale)
{
name = new char[1024];
setName(initName);
born = initBorn;
male = isMale;
cout << "Constructor: Person(const char, int , bool)" << endl;
}
~Student()
{
cout << "To destroy object: " << name << endl;
delete [] name;
}
void setName(const char * s)
{
strncpy(name, s, 1024);
}
void setBorn(int b)
{
born = b;
}
// the declarations, the definitions are out of the class
void setGender(bool isMale);
void printInfo();
};
void Student::setGender(bool isMale)
{
male = isMale;
}
void Student::printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
int main()
{
Student * class1 = new Student[3]{
{"Tom", 2000, true},
{"Bob", 2001, true},
{"Amy", 2002, false},
};
class1[1].printInfo();
delete class1;
delete []class1;
return 0;
}
bash
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Name: Bob
Born in 2001
Gender: Male
To destroy object: Tom
数组调用析构函数delete class1
, 只会调用第一个对象的析构函数,后面的对象不会被调用
数组调用析构函数 delete [] class1
,则会调用全部对象的析构函数
bash
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Name: Bob
Born in 2001
Gender: Male
To destroy object: Amy
To destroy object: Bob
To destroy object: Tom
3-this
pointer
Why is this
needed
- How does a member function know which name?
this
Pointer
- All methods in a function have a
this
pointer - It is set to the address of the object that invokes the method
this.cpp
cpp
#include <iostream>
#include <cstring>
using namespace std;
class Student
{
private:
char * name;
int born;
bool male;
public:
Student()
{
name = new char[1024]{0};
born = 0;
male = false;
cout << "Constructor: Person()" << endl;
}
Student(const char * name, int born, bool male)
{
this->name = new char[1024];
this->setName(name);
this->born = born;
this->male = male;
cout << "Constructor: Person(const char, int , bool)" << endl;
}
~Student()
{
cout << "To destroy object: " << name << endl;
delete [] name;
}
void setName(const char * name)
{
strncpy(this->name, name, 1024);
}
void setBorn(int born)
{
this->born = born;
}
// the declarations, the definitions are out of the class
void setGender(bool isMale);
void printInfo();
};
void Student::setGender(bool isMale)
{
male = isMale;
}
void Student::printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
int main()
{
Student * class1 = new Student[3]{
{"Tom", 2000, true},
{"Bob", 2001, true},
{"Amy", 2002, false},
};
class1[1].printInfo();
delete []class1;
return 0;
}
bash
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Name: Bob
Born in 2001
Gender: Male
To destroy object: Amy
To destroy object: Bob
To destroy object: Tom
4- const
and static
Members
const
Variables
- statements for constants
C++不推荐用 宏
const
Members
const
member variables behavior similar with normal const variablesconst
member functions promise not to modify member variables
cpp
class Student
{
private:
const int BMI = 24;
public:
Student()
{
BMI = 25;//can it be modified?
int getBorn() const
{
born++; //Can it be modified?
return born;
}
};
常量函数,const
放在后面,不然跟前面的const int
相冲突。不可以修改成员变量,born
是不可以被修改的,保证不修改函数里的变量
const.cpp
cpp
#include <iostream>
#include <cstring>
using namespace std;
class Student
{
private:
const int BMI = 24;
char * name;
int born;
bool male;
public:
Student()
{
name = new char[1024]{0};
born = 0;
male = false;
// BMI = 25;//can it be modified?
cout << "Constructor: Person()" << endl;
}
Student(const char * name, int born, bool male)
{
this->name = new char[1024];
setName(name);
this->born = born;
this->male = male;
cout << "Constructor: Person(const char, int , bool)" << endl;
}
~Student()
{
cout << "To destroy object: " << name << endl;
delete [] name;
}
void setName(const char * name)
{
strncpy(this->name, name, 1024);
}
void setBorn(int born)
{
this->born = born;
}
int getBorn() const
{
//born++; //Can it be modified?
return born;
}
// the declarations, the definitions are out of the class
void setGender(bool isMale);
void printInfo();
};
void Student::setGender(bool isMale)
{
male = isMale;
}
void Student::printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
int main()
{
Student yu("Yu", 2000, true);
cout << "yu.getBorn() = " << yu.getBorn() << endl;
return 0;
}
bash
Constructor: Person(const char, int , bool)
yu.getBorn() = 2000
To destroy object: Yu
static
members
static
members are not bound to class instances
cpp
class Student
{
private:
static size_t student_total; // declaration only
public:
Student()
{
student_total++;
}
~Student()
{
student_total--;
}
static size_t getTotal() {return student_total;}
};
// definition it here
size_t Student::student_total = 0;
静态成员不绑定在类对象上,只有一个
static.cpp
cpp
#include <iostream>
#include <cstring>
using namespace std;
class Student
{
private:
static size_t student_total; // declaration only
//inline static size_t student_total = 0; //C++17, definition outside isn't needed
char * name;
int born;
bool male;
public:
Student()
{
student_total++;
name = new char[1024]{0};
born = 0;
male = false;
cout << "Constructor: Person(): student_total = " << student_total << endl;
}
Student(const char * initName, int initBorn, bool isMale)
{
student_total++;
name = new char[1024];
setName(initName);
born = initBorn;
male = isMale;
cout << "Constructor: Person(const char, int , bool): student_total = " << student_total << endl;
}
~Student()
{
student_total--;
cout << "To destroy object: " << name ;
cout << ". Then " << student_total << " students are left" << endl;
delete [] name;
}
void setName(const char * s)
{
strncpy(name, s, 1024);
}
void setBorn(int b)
{
born = b;
}
static size_t getTotal() {return student_total;}
// the declarations, the definitions are out sof the class
void setGender(bool isMale);
void printInfo();
};
void Student::setGender(bool isMale)
{
male = isMale;
}
void Student::printInfo()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Born in " << born << std::endl;
std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}
size_t Student::student_total = 0; // definition it here
int main()
{
cout << "---We have " << Student::getTotal() << " students---" << endl;
Student * class1 = new Student[3]{
{"Tom", 2000, true},
{"Bob", 2001, true},
{"Amy", 2002, false},
};
cout << "---We have " << Student::getTotal() << " students---" << endl;
Student yu("Yu", 2000, true);
cout << "---We have " << Student::getTotal() << " students---" << endl;
class1[1].printInfo();
delete []class1;
cout << "---We have " << Student::getTotal() << " students---" << endl;
return 0;
}
bash
---We have 0 students---
Constructor: Person(const char, int , bool): student_total = 1
Constructor: Person(const char, int , bool): student_total = 2
Constructor: Person(const char, int , bool): student_total = 3
---We have 3 students---
Constructor: Person(const char, int , bool): student_total = 4
---We have 4 students---
Name: Bob
Born in 2001
Gender: Male
To destroy object: Amy. Then 3 students are left
To destroy object: Bob. Then 2 students are left
To destroy object: Tom. Then 1 students are left
---We have 1 students---
To destroy object: Yu. Then 0 students are left
静态函数里面不可以修改非静态数据