1、类的基础知识点
1.1、类和对象
和C中的结构体不同,在C++类中不仅可以定义变量,也可以定义函数。【在C++结构体中也可以定义变量和函数,但是一般情况下都使用类】。
类的成员属性默认都是private;结构体的成员属性默认都是public。
class student
{
public:
// 共有成员(外部接口,可被使用该类的所有代码所使用的)
student();
~student();
void set_age(int age_t);
private:
// 私有成员(只允许本类中的函数访问,而类外部的任何函数都不允许访问)
char name[50];
int age;
protected:
// 保护成员(与private类似,差别表现在继承与派生时)
};
类中的元素称为类的成员;类中的数据称为类的属性或者成员变量;类中的函数称为类的方法或者成员函数。
1.2、类中成员函数定义
(1)声明和定义都放在类体中
// .h文件中
class student
{
public:
// 共有成员(外部接口,可被使用该类的所有代码所使用的)
student();
~student();
void set_age(int age_t)
{
age = age_t;
}
private:
// 私有成员(只允许本类中的函数访问,而类外部的任何函数都不允许访问)
char name[50];
int age;
protected:
// 保护成员(与private类似,差别表现在继承与派生时)
};
(2)声明和定义分离
// .h文件中
class student
{
public:
// 共有成员(外部接口,可被使用该类的所有代码所使用的)
student();
~student();
void set_age(int age_t);
private:
// 私有成员(只允许本类中的函数访问,而类外部的任何函数都不允许访问)
char name[50];
int age;
protected:
// 保护成员(与private类似,差别表现在继承与派生时)
};
// .cpp文件中
void student::set_age(int age_t)
{
age = age_t;
}
1.3、类的作用域
C++类重新定义了一个作用域,类的所有成员都在类的作用域中。在类外使用成员时,需要使用 ::(作用域解析符)来指明成员属于哪个类。
1.4、实例化
用类去创建对象的过程,称为类的实例化。类只声明了类有哪些成员,而并没有为成员分配内存空间。一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。
类是对象的抽象和概括,而对象是类的具体和实例。
1.5、类对象的存储方式
C++程序占用的内存通常分为四个区:
代码区(code area):存放着程序的二进制代码,由操作系统管理。
全局区(static area):存放全局变量,静态变量,以及常量(字符常量和const修饰的全局变量)。
栈区(stack area):存放所有的局部变量,其空间分配释放由编译器管理,当函数结束,局部变量自动被释放。
堆区(heap area):存放所有动态开辟的变量,其空间分配释放由程序员管理。
类对象存储如下:
在类定义时:
类的成员函数是被放在代码区。
类的静态成员变量是存储在静态区的,即实例化的对象并不包括静态变量的创建。
类的静态成员变量,在类的实例化过程中才在栈区或者堆区为其分配内存,是为每个对象生成一个拷贝,所以它是属于对象的。
#include <iostream>
using namespace std;
class student_1
{
public:
void set_age(int age_t);
private:
char name[50];
int age;
static char aa[8];
}std_1;
class student_2
{
public:
private:
char name[50];
int age;
}std_2;
class student_3
{
}std_3;
int main(int argc, char argv[])
{
cout << " " << sizeof(std_1) << endl;
cout << " " << sizeof(std_2) << endl;
cout << " " << sizeof(std_3) << endl;
return 0;
}
输出:
56
56
1
结论:
一个类的大小,实际就是该类中“成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。
注意:
这里的成员变量之和并不是简单的字节数相加,而是还要遵循内存对齐规则。
1.6、this指针
#include <iostream>
using namespace std;
class student
{
public:
void set_id(int grade_id__t, int class_id_t);
void display_id_0()
{
cout << "grade_id: " << grade_id << ", class_id: " << class_id << endl;
}
void display_id_1()
{
cout << "grade_id: " << this->grade_id << ", class_id: " << this->class_id << endl;
}
private:
char name[50];
int age;
int grade_id;
int class_id;
};
void student::set_id(int grade_id__t, int class_id_t)
{
grade_id = grade_id__t;
class_id = class_id_t;
}
int main(int argc, char argv[])
{
student std_1, std_2;
std_1.set_id(10, 11);
std_2.set_id(101, 34);
std_1.display_id_0();
std_1.display_id_1();
std_2.display_id_0();
std_2.display_id_1();
return 0;
}
结果为:
grade_id: 10, class_id: 11
grade_id: 10, class_id: 11
grade_id: 101, class_id: 34
grade_id: 101, class_id: 34
问题一:
对于上述程序,std_1和std_2各自有不同的内存空间,而成员函数set_id中却并没有指定要对哪一个对象的成员进行操作,那么当std_1调用时函数是如何知道操作的对象是哪一个呢?
答:
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
this指针的特性:
this指针的类型:类的类型* const,this在函数体内不可修改。
只能在“成员函数”的内部使用。
this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针。
this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
问题二:
this指针的存储位置在哪里?
答:
临时变量都是存储在栈上的,因此this指针作为形参,存储在栈区。
问题三:
this指针可以为空指针吗?
答:
this指针可以为空指针,但切忌通过nullptr去访问指向的数据。
#include <iostream>
using namespace std;
class student
{
public:
void set_id(int grade_id__t, int class_id_t);
void display_id()
{
cout << "grade_id: " << grade_id << ", class_id: " << class_id << endl;
}
void display()
{
cout << "grade_id and class_id" << endl;
}
private:
char name[50];
int age;
int grade_id;
int class_id;
};
void student::set_id(int grade_id__t, int class_id_t)
{
grade_id = grade_id__t;
class_id = class_id_t;
}
int main(int argc, char argv[])
{
student *std_1 = nullptr;
std_1->display(); // 执行成功
std_1->display_id(); // 执行失败
return 0;
}
成员函数display()执行成功,而成员函数display_id()执行失败。首先nullptr地址我们是没有访问权限的,非法访问会使程序崩溃。
display()执行成功,因为访问的是成员函数,成员函数不在对象内,就不会对指针解引用,std_1->的作用仅仅是指明了函数的类域,而函数内也没有使用到this指针,所以不会报错。
display_id()执行失败,是因为在打印的时候调用了成员变量grade_id和class_id,而std_1又指向了nullptr,相当于访问了nullptr地址处的数据,因此程序崩溃。
2、
3、
4、
5、
End、结语
感谢参考的文档;参考的文档太多,不做一一列举。
感谢大家提供的建议;