1.类的定义
类是面向对象语言特有的语法,在面向对象语言中所有的变量和函数统称为对象,并且类里面可以对象。
语法
class ClassName { // 类体:由成员函数和成员变量组成 void Init(); int a; }; //class为定义类的关键字,ClassName为类名,{}中为类的主题,注意类定义结束时后面分号不能省略。 //类中的内容称为类的成员:类的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数。
类的定义方式
- 声明和定义全部放在类体(注意:成员函数如果在类中定义,编译器可能会将其当称)
// 成员函数声明定义都在类中 class xty { public: void Print() { cout << "defined in class" << endl; } private: int a; int b; };
- 类的声明放在.h的文件中,成员函数定义在.cpp文件中,注意:定义成员函数名前需要加类名::
// .h文件 class xty2 { public: //声明 void Print(); private: int a; int b; }; // .cpp定义 void xty2::Print() { cout << "defined in class" << endl; }
工程项目实践中,更推荐声明和定义分开来处理。
有声明说明语法没问题,可以编译过;有定义,链接的时候就能根据符号表找到地址了,可以链接过
2.类的访问限定符
访问限定符:1.public(公有);2.protected(保护);3.private(私有)
2.1 访问限定符的特点
- public修饰的成员在类外可以直接被访问。
- protected和private修饰的成员在类外面不能被直接访问
- 访问权限的作用域从该访问限定符出现的位置开始直到下一个访问限定符出现为止
- 如果后面没有访问限定符,作用域到 } 即类结束
- class的默认访问权限为private,struct为public(因为struct要兼容C)
class Xty { public: void Print() { cout << "defined in class" << endl; } private: int a = 10; int b; int c; }; int main() { //声明xp对象 Xty xp; xp.a = 10; //报错,因为a 为私有,所以对xp.a不可访问 int z = xp.a; //报错,因为a 为私有,所以对xp.a不可访问 xp.Print(); //可以运行,Print成员函数为公有,因此可以在类外面访问 return 0; }
2.2 struct与class的区别
- 首先,struct是C语言的关键字,C++为了兼容C的语法,将struct类默认权限变为公有,这样在类外面也能通过对象访问;而class默认为私有,类外的不能随便访问。
3. 三大特性
C++具有三大特性:继承、封装和多态。
3.1 封装
将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开的接口来和对象进行交互。封装本质上是一种管理,让用户更安全更方便的使用类。
4.类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类外定义成员时,需要使用::域作用限定符。
class Xty { public: void Print(); private: int a = 10; int b; int c; }; //在类外面定义成员时,需加上域名,来说明Print是属于Xty这个域里面的 void Xty::Print() { cout << "hello world!" << endl; }
5.类的实例化
用类型创建类称为类的实例化。
- 类是对对象进行描述的,是一个模型,定义出的类,并没有分配出实际的内存空间。
- 一个类可以实例化(创建)出多个对象,对象占用实际的物理空间,存储类成员变量
class Xty { public: void Print(); int a; int b; int c; }; //在类外面定义的成员函数 void Xty::Print() { cout << "hello world!" << endl; } int main() { //Xty的类创建出xp的对象 Xty xp; //是给xp的对象赋值,而不是给类赋值 xp.a = 10; xp.b = 20; xp.Print(); return 0; }
6.类对象模型
编译器是如何存储对象的呢?
先看一段代码示例:
//类中既有成员变量又有成员函数 class X1 { public: void Print() { cout << "hello world" << endl; } private: char a; }; //类中只有成员变量 class X2 { private: int a; }; //类中什么也没有 class X3 { }; int main() { X1 x1; X2 x2; X3 x3; cout<<"x1 : " << sizeof(x1) << endl; // 1 cout<<"x2 : " << sizeof(x2) << endl; // 4 cout<<"x1 : " << sizeof(x3) << endl; // 1 return 0; }
观察可以看出,对象的成员变量占用存储空间,而成员函数不占用对象的空间,并且类对象中什么都没有时,给1B来占位,标识该对象存在。
事实上:成员变量和成员函数是分开存储的,只有成员变量占用对象的存储空间,而该类的所有对象的成员函数,同统一存储在公共代码区,并且所有对象共用该代码。
7.this指针
先看下面一段代码:
class Time { public: void Init(int h, int min, int s) { _h = h; _min = min; _s = s; } void Print() { cout << _h << ":" << _min << ":" << _s << endl; } private: int _h; int _min; int _s; }; int main() { Time t1; Time t2; t1.Init(10, 20, 3); t2.Init(5, 10, 1); t1.Print(); // 10:20:3 t2.Print(); // 5:10:1 }
因为成员函数在公共区,而成员函数有Print函数和Init函数,C++是如何知道当调用t1.Init()函数时,怎么知道我是要使用t1对象,还是要使用t2对象的呢?
答:C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要传递,编译器自动完成,这个指针就是“this指针”。
7.1 this指针的特性
- this指针的类型:类的类型 *const,在成员函数中,不能给this指针赋值
- 只能在成员函数内部使用。
- this指针的本质是成员函数的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是“成员函数”第一个隐藏的指针形参,一般情况下由编译器通过ecx寄存器自动传递,不需要用户传递。
this指针是存在的,只不过是编译器自动帮我们完成的,我们可使用,也可以不使用
实参和形参不能显示的传递和接受this指针,会报错(不能编译通过)。如下图:
但是可以在成员函数内部使用this指针(可以编译通过),如下图:
7.2 this指针相关问题
- this指针存在哪里?this指针为形参,形参存在栈区。
- this指针可以为空吗?this指针可以为空,当访问成员函数时,是直接去公共区寻找函数,而不会通过解引用去寻找函数,因此不会对空指针产生解引用,所以可以。