类与面向对象
**C++**面向对象的三大特性:封装
、继承
、多态
。
面向对象(Object-Oriented)是一种软件开发的方法论,它将程序中的数据和操作数据的逻辑封装在一起,以形成对象的概念,对象可以互相之间进行交互和通信。
博客源地址:修能的博客
名词解释
什么是类?
类(Class
): 类是对象的抽象,它定义了一个对象的属性和方法。类可以看作是创建对象的模板或蓝图。
struct 和 class 之间的区别
struct 和 class 之间的区别 在许多编程语言中,包括C++和C#等,都支持使用struct
和class
来定义数据结构和数据类型。下面是struct
和class
之间的主要区别:
- 成员的默认访问权限:
class
是私有,struct
公有。 - 继承能力:
class
支持继承,struct
不支持继承。 - 分配方式:
class
是引用类型数据(堆区),struct
是值类型数据(栈区)。 - 默认的拷贝方法:
class
是浅拷贝,struct
逐成员拷贝。
什么是对象?
对象(Object
)是****类的实例**,它是具体的、实际存在的数据实体,具有类所定义的属性和方法。
什么是封装?
封装(Encapsulation
): 封装是将数据和操作数据的方法绑定在一起,通过限制对数据的访问,确保数据的完整性和安全性。
什么是继承?
继承(Inheritance
): 继承允许一个类继承另一个类的特性和行为,从而实现代码的重用和扩展
什么是多态?
多态(Polymorphism
): 多态允许使用统一的接口来操作不同类型的对象,提供了代码的灵活性和可维护性。
封装
在面向对象编程中,封装可以帮助保护数据和方法的访问权限,确保对数据的访问和操作符合预期并符合设计意图。
访问权限
权限的控制有三种:
public
公共权限
公开访问表示成员(属性或方法)对所有对象和其他类可见,并且可以被直接访问和调用。private
私有权限
私有访问表示成员仅对所属类内部可见,其他类无法直接访问私有成员。私有成员只能被类内部的方法所使用。protected
保护权限
保护访问类似于私有访问,但对于继承关系中的子类是可见的。即子类可以访问基类的保护成员,但其他类无法直接访问。但是仅仅也只是保护权限的内容。
私有权限
在将成员设置为私有时,一般会写一些公共方法来对私有成员进行读写的操作,即get()
和set()
方法。
这样就可以对数据的读写性进行控制,只要不写私有成员get
或set
方法就可以了。
这样还可以对数据的输入进行控制,只要在set()
中添加判断逻辑,就可以控制数据的有效范围。
如何判断两个对象是否相等
有两种方法:
- 定义全局函数(不建议)
- 定义成员函数
bool student::isEqual(student stu)
{
return stu.getName() == this->Name && stu.getGender() == this->Gender && stu.getAge() == this->Age;
}
对象的初始化和清理
构造函数
在实例化对象的时候自动的调用。
如果不写构造函数,对象会默认创建对象的默认的无参构造函数。
函数名与类名相同。
构造函数的分类
按参数分:
- 无参构造
- 有参构造
按调用的分类:
-
拷贝构造
student(const student &stu); student s3(s1);
const
是因为不能改变原先对象的值&
引用是因为防止递归调用 -
显式构造
student s1 = student("xiunneg",student::GENDER::Male, 13);
student("xiunneg",student::GENDER::Male, 13);
是一个匿名对象
。 -
隐式构造(不建议,仅仅适用于单个参数的构造)
拷贝构造注意事项
当对象被以值的形式传递时会调用到拷贝构造函数。。
析构函数
用于对象的销毁前会自动调用来销毁对象。
函数名为:~类名()
深拷贝和浅拷贝
浅拷贝: 简单的赋值拷贝操作
深拷贝: 在堆区重新申请空间,进行拷贝操作
这两种拷贝的区别就是对于指针类型的数据的操作。
以下用A
对象指源对象,B
对象指通过拷贝构造A
对象而得到的对象。
浅拷贝对于指针类型的复制只会复制指针的值,不会拷贝指针指向的值,就是说两个对象中的指针成员所指向的是同一个内存空间,通过A
对象可以修改通过浅拷贝复制构造出的B
对象的值。
深拷贝要求将指针的数据类型重新分配内存地址,再去赋值,这样就在修改B
对象时不会修改A
对象的数据了,因为指针指的不是同一块内存地址了。
inline Person::Person(const Person &other)
{
data = new int;
*data = *(other.data);
cout << "深拷贝" << endl;
}
inline Person::Person(const Person &other)
{
data = other.data;
cout << "浅拷贝" << endl;
}
初始化列表
用于初始化属性的语法:
class Class{
private:
int A;
int B;
int C;
public:
Class(int a,int b,int c) : A(a),B(b),C(c) {};
}
对象成员
类的成员也可以是别的类的对象。
那么它们的构造函数和析构函数的调用顺序是怎样的呢?
遵循一个原则,谁在外部谁先构造,谁在内部谁先析构。
静态成员
被关键词static
修饰过变量或者函数被称为静态成员,它们有以下特点:
- 静态成员属性:它是属于类本身的属性,而不是属于实例化对象的属性,也就是说所有的实例化对象共有这个成员,所有的对象实例的这个值是一样的。
- 静态成员函数:它无法访问非静态成员属性,也无法使用
this
指针。静态成员函数可以通过类名来直接调用,不需要通过类的实例。 - 静态成员的访问控制:静态成员遵循类的访问控制规则。私有的静态成员只能被类内的函数访问,公有的静态成员可以被任何使用类的代码访问。
静态成员一般不会通过实例来访问,都是使用类名来进行访问:classname::static member
。
C++对象模型
成员变量和成员函数分开存储
空对象的占用内存空间是1,是因为编译器会将空对象分配一个字节空间,为了区分对象占内存的位置。
对象的内存空间中只会存储对象中的非静态的成员属性和虚函数表,函数成员存储在类的代码段中。
静态成员属性在类内部声明,在类的代码段中进行定义和初始化,并且存储在全局数据区(Global Data Segment)
this指针
this指针
的本质是classname* const this
,是一个指针常量。
一个非静态成员函数只会生成一份函数实例,也就是多个同类型的对象会去调用同一个函数实例,那如果区分调用的对象就成了一个问题。
this指针
可以解决这个问题。
this指针
是C++ 提供的特殊对象指针,this指针指向被调用的成员函数所属的对象。
用处如下:
- 当函数的参数与类的属性同名时,需要通过
this
来区分。 - 在类的非静态成员函数返回对象本身时,可使用
return *this
,同时函数的返回类型也要写成类对象的引用类型Person& func(Person p1) {return *this}
,否则返回的是一个新的值,利用是函数可以链式调用。
const修饰的成员函数
-
常函数
成员函数后加
const
后我们称这个函数为常函数。其本质是修饰了this
指针。void Testfunc() const {}; classname* const this ----> const classname* const this
被设置为常函数后,函数的内部不能修改成员属性,也就是设置了该函数为只读。
如果想要在常函数中修改属性,只要在想要修改的对象前用
mutable
修饰即可。 -
常对象
声明对象前加
const
称该对象为常对象常对象只能调用常函数。