前言
类与对象(一)
文章目录
- 一、面向对象和面向过程的对比
- 二、类的引入
- 2.1 C++中的结构体
- 2.2 类
- 2.3 类定义方法
- 2.4 修饰限定符
- 2.5 封装
- 2.6 类的实例化
- 2.7 类对象的大小
- 三、this指针
- 3.1 this 指针的使用
一、面向对象和面向过程的对比
面向过程编程是将程序看作一系列的步骤或过程,然后逐步完成各个步骤,从而实现一个程序的方法。而面向对象编程是将问题分解为对象,每个对象包含数据(属性)和操作数据的方法(方法)。
以将大象装进冰箱为例:
面向对象编程(OOP):
- 大象对象: 有属性(大小、重量)和方法(进入冰箱)。
- 冰箱对象: 有属性(容量、门的状态)和方法(打开门)。
面向过程编程:
- 过程: 分解为步骤。打开冰箱的门,把大象放进去,关闭门。
我们知道面向过程的编程语言有C语言,现在我们来认识一下面向对象编程的编程语言的代表之一——C++。
二、类的引入
2.1 C++中的结构体
在C语言中我们可以使用struct
(结构体)来自定义类型,同样在C++也有结构体的使用,但有所不同:
C++中的struct
的特点:
-
默认访问修饰符: 在C++中,
struct
的成员默认是公有的(public,访问限定修饰符),与C语言中相同。 -
支持成员函数: 与C不同,C++中的
struct
可以包含成员函数。// 在C++中的struct示例 struct Person { // 成员变量 char name[50]; int age; // 成员函数 void displayInfo() { cout << "Name: " << name << "\nAge: " << age << endl; } };
-
继承和访问控制: C++中的
struct
也可以继承其他结构体或类,并且支持访问控制,包括私有、保护和公有继承。// 基类 class Animal { public: void eat() { cout << "动物在吃东西。" << endl; } }; // 派生类 struct Dog : public Animal { // 公有继承 void bark() { cout << "狗在叫" << endl; } };
C++中,struct
可以更多地用于实现类似于类的结构。
2.2 类
初始版本的 C++ 在设计时候的一个目标是与 C 语言保持高度的兼容性,以便现有的 C 代码可以逐渐迁移到 C++ 中。因此保留了struct,并稍微扩展了其功能,可以包含函数,增加修饰限定符等。但struct的访问权限是默认是公有的,因此,C++中引入了类的概念。
C++中,类是一种用户自定义的数据类型,在语法上与struct
非常相像。
类的基本结构包括成员变量(类的属性) 和 成员函数(类的方法):
//class为关键字 Time为类名
class Time {
public:
int hours; //小时
int minutes; //分
int seconds; //秒
private:
// 设置时间
void setTime(int h, int m, int s);
// 显示时间
void displayTime();
};
2.3 类定义方法
有两种主要的类定义方式:定义在类外部的方式和定义在类内部的方式。
1. 定义在类外部的方式:
类的声明通常放在头文件(.h 文件)中,而类的定义则放在源文件(.cpp 文件)中。注意:成员函数定义时名字前需要加类名::,例如 int MyClass::getVar() const
示例:
// MyClass.h
#pragma once
class MyClass {
private:
int myVar;
public:
MyClass(); // 声明构造函数
void setVar(int value); // 声明成员函数
int getVar() const; // 声明成员函数
};
// MyClass.cpp
#include "MyClass.h"
MyClass::MyClass() {
myVar = 0;
}
void MyClass::setVar(int value) {
myVar = value;
}
int MyClass::getVar() const {
return myVar;
}
2. 定义在类内部的方式:
类的声明和定义都放在类的内部。
示例:
// MyClass.h
#pragma once
class MyClass {
private:
int myVar;
public:
MyClass() {
myVar = 0;
}
void setVar(int value) {
myVar = value;
}
int getVar() const {
return myVar;
}
};
2.4 修饰限定符
在C++中,修饰限定符用于控制类中成员的访问权限。C++有三个主要的修饰限定符:public
、protected
和private
。
- public: 成员被声明为公有,可以在类的外部和内部访问。
- protected: 成员被声明为受保护的,可以在类的内部和派生类中访问,但在类的外部不能直接访问。
- private: 成员被声明为私有,只能在类的内部访问,不能在类的外部或派生类中直接访问。
修饰限定符通常出现在类的定义中,用于指定类成员的访问权限。以下是一个简单的示例:
class MyClass {
public:
// 公有成员
int publicVar;
// 公有成员函数
void publicFunction() {
// 可以访问公有、受保护、私有成员
publicVar = 1;
protectedVar = 2;
privateVar = 3;
}
protected:
// 受保护成员
int protectedVar;
private:
// 私有成员
int privateVar;
};
在上面的示例中,publicVar
是公有成员,可以在类的外部直接访问。protectedVar
是受保护成员,只能在类的内部和派生类中访问。privateVar
是私有成员,只能在类的内部访问。
需要注意的是:class的默认访问权限为private,struct为public(因为struct要兼容C,这也是为什么要引入类的原因)
2.5 封装
封装是面向对象编程(OOP)的一个核心概念,它指的是将数据和操作数据的方法封装在一个单一的实体(类)中,并对外部隐藏对象的内部实现细节。封装通过将数据成员私有化,并提供公有的成员函数来实现,使得外部代码无法直接访问对象的内部数据,而是通过类的接口进行交互。
封装的主要目的有以下几点:
-
隐藏实现细节: 封装允许将实现细节隐藏在类的内部,使得外部代码无法直接了解或修改类的内部数据结构和实现。
-
简化接口: 封装通过提供公有的接口(成员函数)来与对象进行交互,使得外部代码只需关心如何使用对象,而不需关心对象的内部工作方式。
-
提高代码的模块性: 封装将对象的实现细节封装在一个单一的单元中,使得代码模块化,易于维护和重用。
简单点说,封装就像是你有一辆车,但你不需要知道引擎是怎么工作的,也不需要了解车轮是如何旋转的。你只需要知道一些关于这辆车的基本信息,比如怎么加速、怎么刹车,这就是车的接口。引擎和其他细节都被封装在车的内部,对你来说是不可见的。
2.6 类的实例化
类就像建筑设计图,对象是按照设计图实际要建造的房子。而实例化就像是在建造房子的过程。
举例:
#include <iostream>
using namespace std;
// 定义一个简单的类
class Car {
public:
// 成员变量
string brand;
int year;
// 构造函数
Car(string b, int y) : brand(b), year(y) {}
// 成员函数
void displayInfo() {
cout << "Brand: " << brand << ", Year: " << year << endl;
}
};
int main() {
// 声明并实例化 Car 类的对象
Car myCar("Toyota", 2022);
// 使用对象的成员函数
myCar.displayInfo();
return 0;
}
2.7 类对象的大小
类的大小由其成员变量的大小总和决定,不包括成员函数的大小。成员函数在每个对象中共享相同的代码,因此它们不会增加对象的大小。
成员变量的大小由它们的类型和数量决定。每个基本数据类型(如int、double等)在内存中占用的空间是确定的,而类类型的大小取决于其成员变量的大小。
考虑一个简单的示例:
class MyClass {
public:
int integerVar;
double doubleVar;
char charVar;
void func1();
void func2();
};
int main() {
MyClass c1;
cout << "c1的大小为" << sizeof(c1) << endl;
return 0;
}
那么MyClass
类的对象大小将是24字节,当然这是在默认对齐数为8时的大小。
对象的大小也受到内存对齐的影响,可以参考这篇博文【C语言】自定义类型:结构体。
三、this指针
this
指针是一个特殊的指针,它指向当前对象的地址。
this
指针并不是一个明确存在于内存中的变量,而是编译器在代码生成阶段处理的一种机制,用于传递当前对象的地址给成员函数。
this
指针的存在是因为成员函数需要知道它们是在哪个对象上调用的,以便正确地访问该对象的成员变量和成员函数。
当你在类的成员函数中使用成员变量或调用成员函数时,编译器会隐式地将 this
指针传递给该函数,使得函数内部可以通过 this
指针来引用当前对象。
3.1 this 指针的使用
在类的成员函数中,可以使用 this 指针来引用当前对象的成员变量和成员函数。它允许在成员函数中访问当前对象的成员,即使成员的名称与参数名称相同也能够正确引用。
在传参及接收参数时不能显式地标出this。
class MyClass {
private:
int _x;
public:
void setX(int x) {
this->_x = x; // 使用this指针引用成员变量
//在 C++ 中,如果成员函数中使用的变量名与成员变量名相同,编译器会默认使用成员变量,这是一种默认约定
// _x = x; //或者直接使用成员变量名_x
}
int getX() const {
return this->_x; // 使用this指针引用成员变量
//return _x;
}
};
int main() {
MyClass obj;
obj.setX(42); // 必须隐式地传递this指针给setX函数,即在实参不标出this,也不在形参标出
int value = obj.getX(); // 隐式地传递this指针给getX函数
cout << "value=" << value << endl;
}
如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。