文章目录
- 1.类的引入
- 2.类的访问限定符
- 3.类的作用域
- 4.类的实例化
- 5.类的储存
- 6.this指针
- 6.1this指针的引出
- 6.2this指针的特性
1.类的引入
C++是在C的基础上加以扩展。
在C语言中,我们想要让一个类型含有多种成员变量,我们使用结构体;而在C++中我们可以使用类和结构体。可以说在一般情况下类要优于结构体:
(1)结构体和类都可以包含一组数据成员,这些成员可以是不同的数据类型和集合类型。
(2)结构体和类都可以包含一组成员函数,这些函数可以操作数据成员和执行其他任务。
(3)类比结构体更具有抽象和封装特性,类中的数据成员和成员函数可以通过访问控制符private、protected、public来控制外部访问和使用。
(4)结构体可以进行基本操作,如赋值、比较和作为函数参数传递等。类继承了结构体的这些基本操作。同时,也可实现更多的高级操作,并具有更好的可维护性、可扩展性和数据隐私性。
(5)在C++中,结构体可以看作是一种类,而类可以扮演结构体的角色。
在C++中,类是面向对象编程的基础,它提供了许多方便的编程手段,包括封装、继承、多态和动态内存分配等,使得程序员能够更方便地开发大型、复杂的应用程序。因此,总体来说,相比结构体,类更加灵活、丰富和易用,并且有更多更复杂的应用场景。
用C++定义一个学生类:
#include <string>
using namespace std;// 定义学生类
class Student {string name;int age;double score;
};
2.类的访问限定符
C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
在C++中,类的成员可以使用三种不同的访问限定符来控制成员的可访问性,它们分别是:
(1)private(私有访问限定符):类的私有成员只能被类中的其他成员函数访问,不能被类外的任何函数或对象直接访问。
(2)protected(保护访问限定符):类的保护成员可以被类中的成员函数和派生类中的成员函数访问,但不能被类外的任何函数或对象直接访问。
(3)public(公共访问限定符):类的公共成员可以被类中的成员函数、派生类中的成员函数以及类外的任何函数或对象直接访问。
【访问限定符说明】
(1)public修饰的成员在类外可以直接被访问。
(2)protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)。
(3)访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。
(4)如果后面没有访问限定符,作用域就到 } 即类结束。
(5)class的默认访问权限为private,struct为public(因为struct要兼容C)。
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
用C++定义一个学生类:
#include <string>
using namespace std;// 定义学生类
class Student {
private:string name;int age;double score;
public:Student(string n, int a, double s); // 构造函数string get_name();void set_name(string n);int get_age();void set_age(int a);double get_score();void set_score(double s);void display();
};
3.类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
C++中,类的作用域类似于命名空间。在C++中,类的作用域可以分为两个部分:
(1)类的定义部分:类的定义部分包括在类声明中的所有内容,例如成员变量、成员函数、访问限定符等。这些内容在类外不可见,在类内部可以直接访问,只有在类外使用类名限定符才能访问。
(2)类的成员函数定义部分:类的成员函数定义部分包括在类外定义的所有成员函数。在类声明中声明的成员函数只是一个函数声明,必须在类外部定义成员函数。在函数定义中,可以直接使用类名限定符访问类的成员变量和成员函数,例如className::memberName。
用C++定义一个学生类:
#include <string>
using namespace std;// 定义学生类
class Student {
private:string name;int age;double score;
public:Student(string n, int a, double s); // 构造函数string get_name();void set_name(string n);int get_age();void set_age(int a);double get_score();void set_score(double s);void display();
};// 构造函数的定义
Student::Student(string n, int a, double s) {name = n;age = a;score = s;
}// 学生姓名访问函数
string Student::get_name() {return name;
}// 学生姓名设置函数
void Student::set_name(string n) {name = n;
}// 学生年龄访问函数
int Student::get_age() {return age;
}// 学生年龄设置函数
void Student::set_age(int a) {age = a;
}// 学生成绩访问函数
double Student::get_score() {return score;
}// 学生成绩设置函数
void Student::set_score(double s) {score = s;
}// 显示学生信息
void Student::display() {cout << "姓名:" << name << endl;cout << "年龄:" << age << endl;cout << "成绩:" << score << endl;
}
4.类的实例化
用类类型创建对象的过程,称为类的实例化。
(1)类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个类,来描述具体学生信息。
(2)一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量。
(3)类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。
用C++定义一个学生类:
#include <string>
using namespace std;// 定义学生类
class Student {
private:string name;int age;double score;
public:Student(string n, int a, double s); // 构造函数string get_name();void set_name(string n);int get_age();void set_age(int a);double get_score();void set_score(double s);void display();
};// 构造函数的定义
Student::Student(string n, int a, double s) {name = n;age = a;score = s;
}// 学生姓名访问函数
string Student::get_name() {return name;
}// 学生姓名设置函数
void Student::set_name(string n) {name = n;
}// 学生年龄访问函数
int Student::get_age() {return age;
}// 学生年龄设置函数
void Student::set_age(int a) {age = a;
}// 学生成绩访问函数
double Student::get_score() {return score;
}// 学生成绩设置函数
void Student::set_score(double s) {score = s;
}// 显示学生信息
void Student::display() {cout << "姓名:" << name << endl;cout << "年龄:" << age << endl;cout << "成绩:" << score << endl;
}// 主函数
int main() {// 实例化一个学生对象并设置其属性Student stu("Tom", 18, 90.5);// 显示学生信息stu.display();// 修改学生属性stu.set_name("Jack");stu.set_age(19);stu.set_score(88.5);// 再次显示学生信息stu.display();return 0;
}
5.类的储存
C++ 中的类对象是存储在计算机内存中的,存储方式取决于具体的编译器、操作系统和硬件等因素。一般来说,类对象在内存中的存储是连续的,其中包括成员变量(也称为类数据成员)和成员函数(也称为类成员函数)。
成员变量存储的位置会根据其访问修饰符的不同而分为公有、私有或保护成员。对于公有成员变量,可以通过对象或者指向对象的指针直接访问。而私有成员变量和保护成员变量只能由类内部的成员函数通过 this 指针来访问,其它方式都无法直接访问。
成员函数存储的位置和成员变量不同:类的成员函数是在类外定义的,因此它们不会占用对象存储空间。不同的成员函数有不同的调用方式:对于普通成员函数,有固定的传参方式,会在函数内部调用 this 指针指向的对象;而静态成员函数则不需要通过对象调用,因此没有 this 指针,并且可以被所有对象和类共享。
需要注意的是,在类中定义的静态成员变量在内存中只有一份,不属于对象而是属于类本身。所以,无论有多少个类的对象都只会有一个静态成员变量存储空间。
总的来说,类存储方式是由编译器、操作系统和硬件等多种因素共同决定的,并且不同编译器和平台的存储方式可能存在差异。但是,我们可以通过了解类的访问修饰符和成员函数等基本特性,来更好地理解类在内存中的存储原理以及如何使用和管理类对象的内存。
结构体内存对齐规则
// 类中既有成员变量,又有成员函数
class A1 {
public:void f1(){}
private:int _a;
};
// 类中仅有成员函数
class A2 {
public:void f2() {}
};
// 类中什么都没有---空类
class A3
{};sizeof(A1) : ___4___ sizeof(A2) : ___1___ sizeof(A3) : ___1___
结论:一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐;注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。
6.this指针
6.1this指针的引出
先定义一个日期类:
class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout <<_year<< "-" <<_month << "-"<< _day <<endl;}private:int _year; // 年int _month; // 月int _day; // 日int a;
};int main()
{Date d1, d2;d1.Init(2022,1,11);d2.Init(2022, 1, 12);d1.Print();d2.Print();return 0;
}
对于上述类,有这样的一个问题:
Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
6.2this指针的特性
在 C++ 中,this 是一个指向当前对象的指针,它有以下特性:
(1)this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
(2)只能在“成员函数”的内部使用。
(3)this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
(4)this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。
1.this指针可以为空吗?
this指针是可以为空指针的,但是不能解引用。通常我们不应该让this指针为空指针。
2.this指针存在哪里?
this指针存放在调用函数的栈帧里面,VS下对this指针进行了优化,存放在寄存器ECX里面。
需要注意的是,this 指针是常量指针,它指向的地址不能被修改。因此,在成员函数中不能直接修改 this 指针的指向,否则会导致编译错误。另外,在一些特殊场合下,this 指针的值可能会被修改(如使用 const_cast 显式地转换掉 const 属性),但这样做通常是不被推荐的,因为会破坏对象的封装性和安全性。
这些就是C++中类和对象的简单介绍了😉
如有错误❌望指正,最后祝大家学习进步✊天天开心✨🎉