1.类的定义
2.类的访问限定符及封装
3.类的作用域
4.类的实例化
5.类的对象的大小计算
6.类成员函数的this指针
1.类的定义
class className
{//类体:由成员函数和成员变量组成
};
class是声明类的关键字,className是类的名字,花括号内为类的主体,注意花括号后面有一个分号。
类体中的内容为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或成员函数。
成员函数的两种定义方式:
1声明和定义都在类内,需注意:这种方法定义的成员函数可能会被编译器当成内联函数处理。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{
public://先不管这个publicvoid hello(){cout << "hello world" << endl;}
};
int main()
{stu a1;a1.hello();return 0;
}
2.类内声明,类外定义
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{
public://先不管这个publicvoid hello();
};
void stu::hello()
{cout << "hello world" << endl;
}
int main()
{stu a1;a1.hello();return 0;
}
3.类声明放在1头文件,成员函数定义在源文件
//name.h
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{
public://先不管这个publicvoid hello();
};
//name.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "name.h"
void stu::hello()
{cout << "hello world" << endl;
}
//test.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "name.h"
int main()
{stu a1;a1.hello();return 0;
}
2.类的访问限定符及封装
2.1访问限定符
c++实现封装的方式:用类讲对象与方法结合在一起,让对象更加完善,通过访问权限选择性的将接口提供给外部的用户使用。
1.public修饰的成员在类外可以直接访问
2.protect和private修饰的成员在类外不能直接访问(现阶段,protect和private没什么区别),但是在类内可以直接访问
3.访问权限的作用域从该访问限定符开始,直到下一个访问限定符结束。如果后面没有访问限定符了,那就到花括号结束,
4.class的默认访问权限是private。
2.2封装
面向对象的三大特性:封装,继承,多态。
封装:将数据和操作数据的方法有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象交互。封装的本质上是一种管理,让用户方便使用类。
3.类的作用域
类定义了一个新的作用域,简称类域,类的所有成员都在类的作用域中。在类外定义成员时,需要使用作用域运算符(::)说明成员属于哪个类域。(类内声明,类外定义)
4.类的实例化
用类类型创建对象的过程,叫做类的实例化
1.类是对对象描述,类的声明不占用内存空间
2.一个类可以实例化多个对象,实例化出的对象占用实际的物理空间,存储类的成员变量
3.一个对象只对应着一个类,类和对象是一对多的关系
4.类可以理解成图纸,对象可以被理解成房子,房子占面积,但图纸不占
5.类的对象的大小计算
对象当中不存储成员函数,也不存成员函数的指针,成员函数表实际上存储在公共代码区。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{
public:void hello(){cout << "hello world" << endl;}
};
int main()
{stu a1;a1.hello();return 0;
}
所以这里的对象a1当中并没有成员函数,实际上这里是根据对象(a1)所对应的类(stu)到公共代码区找成员函数表。
所以,对象中只存成员变量,这里也有内存对齐,规则和结构体一样。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{};
int main()
{cout << sizeof(stu);return 0;
}
空类也有一个字节的大小,用于表示对象的存在。
6.类成员函数的this指针
1.this指针类型:类类型* const,即成员函数中,不能改变this指针
2.this指针只能在成员函数内部使用
3.this指针实质上是成员函数的形参,当对象调用成员函数时自动将对象的指针作为实参传给形参this,所以this也不存在于对象中
4.this指针是隐含的指针形参,不能显式写,但是能显式用
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{
public:void hello(stu this){cout << "hello world" << endl;}
};
int main()
{stu a1;a1.hello(&a1);return 0;
}
这就叫显式写,是错的。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{
public:int a;void hello(){this->a = 1;cout << "hello world" << endl;}
};
int main()
{stu a1;a1.hello();return 0;
}
这就叫显式用,是对的。
题目1:这段代码能运行吗?
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{
public:void print(){cout << "hello" << endl;}
};
int main()
{stu* a1 = nullptr;a1->print();return 0;
}
前面说过,访问成员函数是通过类名到公共代码区找成员函数表而访问的,并不是通过对象访问的,所以这里的a1虽然是空指针,但并没有对其解引用!
将空指针传给this,只要不通过this访问成员变量就不会出错!
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{
public:void printa(){cout << "a" << endl;}void print(){this->printa();cout << "hello" << endl;}
};
int main()
{stu* a1 = nullptr;a1->print();return 0;
}
同理,这个也是对的,这里的this是对象的地址,访问成员函数不会由对对象指针的解引用
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class stu
{
public:int a;void print(){this->a = 1;cout << "hello" << endl;}
};
int main()
{stu* a1 = nullptr;a1->print();return 0;
}
这里就会运行崩溃了(不是编译错误!!!),因为这里通过this访问成员变量,存在对空指针的解引用!!!