目录
1.回顾结构体
struct Student
{
char name[4];
int born;
bool male;
};
struct Student stu;
strcpy(stu.name, "Yu");
stu.born = 2000;
stu.male = true;
缺点:
a)无法检查数据正确与否
b)用指针操作容易越界跑到别的地方去
使用类解决
2.类
class Student
{
public://访问限定符
char name[4];
int born;
bool male;
void setName(const char * s)
{
strncpy(name, s, sizeof(name));
}
void setBorn(int b)
{ ...
Student yu;//实例化对象
yu.setName("Yu");//让数据操作更加安全
3.成员函数可以放在哪里
class Student
{
private:
char name[4];
int born;
bool male;
public:
void setName(const char * s)//inline函数
{
strncpy(name, s, sizeof(name));
}
void setBorn(int b) //inline函数
{
born = b;
}
void setGender(bool isMale);//只放一个函数声明
void printInfo();
};
inline void Student::setGender(bool isMale)//在类外定义inline函数是内置函数
{
male = isMale;
}
void Student::printInfo()//不是inline
{
cout << "Name: " << name << endl;
cout << "Born in " << born << endl;
cout << "Gender: " << (male ? "Male" : "Female") << endl;
}
默认属性(变量)一般定义为私有,方法和行为(函数)定义为公有的
复杂函数写外面
简单函数写里面
4.文件结构
如果程序比较大,写在hpp里面比cpp好,编译时间短
类的声明写在hpp
函数定义在cpp
声明与定义分开
编译器四个阶段,预处理,编译,汇编,链接
在hpp文件中,只声明不定义
空参构造直接给default,没必要定义,但有参的不能有默认参数,不然不能有空参构造
this是本对象
定义文件定义静态区变量(所有对象共享独此一份)
5.#include<>和#include“”
<>:编译器从编译器指定include路径找头文件
“”:从编译器指定的路径找,还会当前cpp目录下面找
6.类里面的构造函数和析构函数
结构体:申请内存(内存里的数据是乱的(没有初始化))
类:申请内存和调用构造函数(对对象里面的数据成员进行初始化)
没有定义构造函数,编译器会自动生成一个构造函数(没有参数,函数体也是空的)
注意:不能在类声明中对数据成员初始化
用户不能调用构造函数(编译器调用)
定义构造函数
class Student
{
private:
// ...
public:
//构造函数(不需要用户来调用它,而是在建立对象时自动执行)
Student()//函数名和类名完全一样,没有返回值,在public里
{
name[0] = 0;//
born = 0;
male = false;
}//可重载,只要参数列表不同(参数个数或者类型不相同)
Student(const char * initName, int initBorn, bool isMale)//带参数的构造函数
//对不同对象赋予不同初值
{
setName(initName);
born = initBorn;
male = isMale;
}
};
Student(const char * initName): born(0), male(true)//简化版
//用参数初始化表对数据成员初始化
{
setName(initName);
}
定义析构函数(函数没有参数,不能被重载,只能有一个)
注:对象先构造的后析构,后构造的先析构
析构函数调用时机:对象被销毁时被调用
析构在堆区开辟的内存
class Student
{
// ...
public:
Student()
{
name = new char[1024]{0};//不释放会导致内存泄漏,程序消耗的内存越来越多
born = 0;
male = false;
cout << "Constructor: Person()" << endl;
}
~Student()//释放内存关闭文件断掉网络或其他操作
{
delete [] name;
}
};
7.对象数组与对象指针
对象数组(对象数组的每一个元素都是同类的对象)
对象指针(对象空间的起始地址就是对象的指针)
Student * class1 = new Student[3]{
{"Tom", 2000, true},
{"Bob", 2001, true},
{"Amy", 2002, false},
};
delete class1;//只会调用第一对象析构函数
delete []class1;//都会调用(推荐使用)
8.this指针
(指向本类对象的指针,它的值是当前被调用的成员函数所在的对象的起始地址)
Student yu = Student{"Yu", 2000, true};//yu(对象)
//Student yu("Yu", 2000, true);
Student amy = Student{"Amy", 2000, false };
yu.setName("yu");
amy.setName("Amy");//两个对象用同一个函数,系统不知道怎么分别引用yu,
amy中的数据成员
name: "Yu" born: 2000 male: true |
name: "Amy" born: 2001 male: false |
不知道哪个对象的name
void setName(const char * s)
{
strncpy(name, s, 1024);
}
void setBorn(int b)
{
born = b;
}
void setBorn(int b)
{
this->born = b;//没有歧义可以省略
}
void setBorn(int born)
{
this->born = born;
}
// this->born(成员变量)
//born(参数变量)
8.类里面的const和static
const
数据成员不被改变的对象,常对象必须要有初值
#define VALUE 100(c推荐)
const int value = 100;(c++推荐)
const int * p_int;
int const * p_int;
//一样,指针指向的内容不能透过指针修改
int * const p_int;//内容可修改,指针地址不能改,只能指在那
void func(const int *);
void func(const int &);
//保证数据不变,安全
class Student
{
private:
const int BMI = 24;// const变量
// ...
public:
Student()
{
BMI = 25;//can it be modified?
// ...
}
int getBorn() const// const函数,放在后面
{
//不可修改成员变量
born++; //Can it be modified?错误
return born;
}
};
定义为const的成员函数 不可以修改类的数据成员(只读)
在成员函数内使用类的数据成员时,实际上隐式的引入了 this
static
class Student
{
private:
//静态成员只有一个(不管有多少对象,只有一份数据)
static size_t student_total; //仅声明//typedef unsigned int size_t;
public:
Student()
{
student_total++;
}
~Student()
{
student_total--;//实时知道这个对象创建了多少次
}
static size_t getTotal() {return student_total;}
//静态成员函数主要用来访问静态数据成员,而不访问非静态成员
};
// definition it here
//静态数据成员初始化,但只能在类体外初始化
全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后有系统释放。
所以在静态成员在对象创建之前就已经存在了,静态成员与对象无关,属于整个类,构造函数是构造某个具体的对象。
静态区的数据在bss段,bss段进入main函数之前就要初始化
c++规定,类中属性为静态变量时,要在类外首次初始化
size_t Student::student_total = 0;
static size_t getTotal() {return student_total;}
//静态函数里不可以修改非静态数据