首页 > 编程语言 >C++快速理解之面向对象

C++快速理解之面向对象

时间:2024-08-11 14:55:00浏览次数:12  
标签:name pStu 对象 age C++ 面向对象 理解 Student cout

文章目录

对象

C++ 中的类(Class)可以看做C语言中结构体(Struct)的升级版
类是一个通用的概念,C++、Python、C#、PHP 等很多编程语言中都支持类,都可以通过类创建对象

C++、Python、C#、PHP 等语言都支持类和对象,所以使用这些语言编写程序也被称为面向对象编程,这些语言也被称为面向对象的编程语言

C语言因为不支持类和对象的概念,被称为面向过程的编程语言

在C语言中,我们会把重复使用或具有某项功能的代码封装成一个函数,将拥有相关功能的多个函数放在一个源文件,再提供一个对应的头文件,这就是一个模块,使用模块时,引入对应的头文件就可以

在 C++ 中,多了一层封装,就是类(Class)。类由一组相关联的函数、变量组成,你可以将一个类或多个类放在一个源文件,使用时引入对应的类就可以

面向对象编程在代码执行效率上绝对没有任何优势,它的主要目的是方便程序员组织和管理代码,快速梳理编程思路,带来编程思想上的革新
面向对象编程是针对开发中大规模的程序而提出来的,目的是提高软件开发的效率
不要把面向对象和面向过程对立起来,面向对象和面向过程不是矛盾的,而是各有用途、互为补充的。如果你希望开发一个贪吃蛇游戏,类和对象或许是多余的,几个函数就可以搞定;但如果开发一款大型游戏,绝对离不开面向对象

============
类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量

创建对象的过程也叫类的实例化,每个对象都是类的一个具体实例(Instance),拥有类的成员变量和成员函数

与结构体一样,类只是一种复杂数据类型的声明,不占用内存空间;
而对象是类这种数据类型的一个变量,或者说是通过类这种数据类型创建出来的一份实实在在的数据,所以占用内存空间

1、定义类

class Student{
public:
    // 成员变量
    char *name;
    int age;
    float score;

    // 成员函数
    void say(){
        cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
    }
};

{ }内部是类所包含的成员变量和成员函数,它们统称为类的成员(Member)
在类定义的最后有一个分号 ; 它是类定义的一部分,表示类定义结束了,不能省略
class是 C++ 中新增的关键字,专门用来定义类
public也是 C++ 的新增关键字,它只能用在类的定义中,表示类的成员变量或成员函数具有“公开”的访问权限
类只是一个模板(Template),编译后不占用内存空间,所以在定义类时不能对成员变量进行初始化,因为没有地方存储数据。只有在创建对象以后才会给成员变量分配内存,这个时候就可以赋值了

2、创建对象

Student leijun;  // 创建对象
class Student leijun;  // 正确,class关键字可要可不要,但是出于习惯我们通常会省略掉 class 关键字
Student leijun;  // 同样正确


除了创建单个对象,还可以创建对象数组:

Student stus[100];

该语句创建了一个 stus 数组,它拥有100个元素,每个元素都是 Student 类型的对象

3、 使用 . 访问成员

#include <iostream>

using namespace std;

// 类通常定义在函数外面
class Student {
public:
    // 成员变量
    char *name;
    int age;
    float score;

    // 成员函数
    void say() {
        cout << name << "的年龄是" << age << ",成绩是" << score << endl;
    }
};

int main() {
    // 创建对象
    Student boy;
    // 通过.可以使用对象中的成员
    boy.name = "小明";
    boy.age = 15;
    boy.score = 92.5f;
    boy.say();

    // 创建对象2
    Student girl;
    // 通过.可以使用对象2中的成员
    girl.name = "菲菲";
    girl.age = 18;
    girl.score = 88.7f;
    girl.say();


    return 0;
}

4、使用 ->访问成员

C语言中经典的指针在 C++ 中仍然广泛使用,尤其是指向对象的指针
上面代码中创建的对象 boy在栈上分配内存,需要使用&获取它的地址,例如:

Student boy;
Student *pStu = &boy;

pStu 是一个指针,它指向 Student 类型的数据,也就是通过 Student 创建出来的对象

当然,你也可以在堆上创建对象,这个时候就需要使用前面讲到的new关键字,例如:

Student *pStu = new Student;

通过 new 创建出来的对象,它在堆上分配内存,没有名字,必须使用一个指针变量来接收这个指针,否则以后再也无法找到这个对象了,更没有办法使用它

内存是程序自动管理的
内存由程序员管理,对象使用完毕后需要用 delete 删除

#include <iostream>

using namespace std;

class Student {
public:
    char *name;
    int age;
    float score;

    void say() {
        cout << name << "的年龄是" << age << ",成绩是" << score << endl;
    }
};

int main() {
    // 创建1个对象,让pStu这个指针变量指向它
    Student *pStu = new Student;
    // 既然pStu指向了一个对象(内存空间),那么就可以调用这个内存空间中的某个成员
    pStu->name = "小明";
    pStu->age = 15;
    pStu->score = 92.5f;
    // 当然也可以调用它里面的函数
    pStu->say();

    // 当不要pStu指向的对象时,需要用delete进行删除(就是释放那个内存空间)
    delete pStu;//对不再使用的对象,记得用 delete 进行回收空间,这是一种良好的编程习惯

    return 0;
}

代码运行visual studio 2022:
错误记录:不能将 “const char *“ 类型的值分配到 “char“ 类型的实体问题
在这里插入图片描述

在这里插入图片描述

解决方法:

在声明p指针指向char数组的时候 前面要加const 不然就会报错
在这里插入图片描述

5、this 指针

#include <iostream>

using namespace std;

class Student {
public:
    char *name;
    int age;
    float score;

    void say() {
        //如果在成员函数中使用name,此时name没有在say函数中定义
        //那么就会往前找这个name函数,此时发现找到了成员变量name
        cout << name << "的年龄是" << age << ",成绩是" << score << endl;
    }

    void setNewAgeScore(int ageTemp, float scoreTemp) {
        age = ageTemp;
        score = scoreTemp;
    }

    void setNewAgeScore2(int age, float score) {
        age = age;
        score = score;
		//在每个成员函数中直接使用,他是在编译的时候自动添加的,他指向了当前对象自己,类似python中的self
    }
};

int main() {

    // 创建一个对象
    Student *pStu = new Student;

    // 调用对象的成员变量
    pStu->name = "小明";
    pStu->age = 15;
    pStu->score = 92.5f;

    // 调用对象的成员函数
    pStu->say();

    // 设置新的年龄、分数
    pStu->setNewAgeScore(16, 98.66f);
    pStu->say();
    pStu->setNewAgeScore2(17, 96.75);
    pStu->say();

    delete pStu;  //删除对象

    return 0;
}

上面代码结果:
在这里插入图片描述
为什么第3次的设置年龄与分数没有起作用呢?

void setNewAgeScore2(int age, float score) {
//首先,整体是一个赋值语句,会将=右侧限制性,即将age这个局部变量的值取出来,17,this->age=17
//既然=右侧已经计算完毕,那么就将这个结果,放到=左侧变量中
//=左侧 又是1个较复杂的计算,this->age,她先用this
//此时this指向一个对象
        this->age = age;
        this->score = score;
		//在每个成员函数中直接使用,他是在编译的时候自动添加的,他指向了当前对象自己,类似python中的self
    }

this 是 C++ 中的一个关键字,它指向当前对象,通过它可以访问当前对象的所有成员

说的直白一点:在成员函数被调用的过程中,会自动生成1个this指针变量,它指向当前调用对象自己,因此可以直接使用this->操作成员变量与成员函数

this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到参数列表中

地址关系:

#include <iostream>

using namespace std;

class Student {
public:
    void printThis() {
        cout << this << endl;
    }
};

int main() {

    Student *pStu1 = new Student;
    pStu1->printThis();
    cout << pStu1 << endl;

    cout << "------------------\n";

    Student *pStu2 = new Student;
    pStu2->printThis();
    cout << pStu2 << endl;

    delete pStu1;  //删除对象
    delete pStu2;  //删除对象

    return 0;
}

在这里插入图片描述
PS:
记录问题

&pStu 和 *pStu 的地址是不一样的。
&pStu 表示的是指针 pStu 本身在内存中的地址。
*pStu 表示的是通过指针 pStu 所指向的 Student 类型的对象。
例如,如果 pStu 存储的地址是 0x1234 ,那么 &pStu 就是 pStu 这个指针变量在内存中的地址,比如 0x5678 ,而 *pStu 表示的是位于 0x1234 处的 Student 对象。

6、构造函数

构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行

怎样定义?
与类名同名没有返回值,可以被重载

有什么用?
通常用来做初始化工作

7、析构函数

一种在对象销毁时,自动调用的函数

怎样定义?
析构函数名称与类名称相同,只是在前面加了个波浪号 ~ 作为前缀,它不会返回任何值,也不能带有任何参数,不能被重载

有什么用?
一般用于释放资源,例如关闭打开的文件,打开的网络socket套接字等

#include <iostream>
#include <string>

using namespace std;

class Student {
public :
    char *name;
    int age;

    // 构造函数
    Student() {
        cout << "执行无参构造函数" << endl;
    }

    Student(char *name) {
        cout << "执行含有一个参数的参构造函数" << endl;
    }

    Student(char *name, int age) {
        cout << "执行含有两个参数的构造函数" << endl;
    }

    // 析构函数
    ~Student() {
        cout << "执行析构函数" << endl;
    }
};

int main() {
    // 创建对象时,自动调用构造函数
    Student *pStu1 = new Student;
    Student *pStu2 = new Student;
    Student *pStu3 = new Student;

    // 销毁对象时,自动调用析构函数
    delete pStu1;
    delete pStu2;
    delete pStu3;

    return 0;
}

在这里插入图片描述

8、重载

函数名相同,形参不同,调用的时候会自动调对应的

案例:

目的:了解怎样让多个对象之间如何产生关联,从而实现发挥面向对象编程的威力

错误记录:
1没有与参数列表匹配的构造函数
构造函数里的参数定义要与成员变量一致

#include <iostream>
using namespace std;

class Gun {
public:
	const char* name;

	Gun(const char* name) { // 添加构造函数
		this->name = name;
	}

	const char* get_name() {
		return this->name;
	}
	void display_info() {
		cout << "name:" << this->name << "\n";
	}
};

class Bullet {
public:
	int kill_power;

	Bullet(int kill_power) {
		this->kill_power = kill_power;
	}
	void display_info() {
		cout << "子弹的威力值:" << this->kill_power << "\n";
	}
};

class Person {
public:
	const char *name;
	Gun* gun;

	Person(const char *name) {
		this->name = name;
	}

	void display_info() {
		cout << "name:" << this->name << "\n";
	}
	void get_gun(Gun* gun) {
		this->gun = gun;
		cout << this->name << " 拿起了" << gun->get_name() << "\n";
	}

};

int main(){

	class Person hero("钢铁侠");
	hero.display_info();

	class Gun gun("AK47");
	gun.display_info();

	hero.get_gun(&gun);

	return 0;
}

在这里插入图片描述

#include <iostream>
using namespace std;


class Bullet {
public:
	int kill_power;

	Bullet(int kill_power) {
		this->kill_power = kill_power;
	}
	void display_info() {
		cout << "子弹的威力值:" << this->kill_power << "\n";
	}
	int get_power() {
		return this->kill_power;
	}
};

class Gun {
public:
	const char* name;
	Bullet* bullet;

	Gun(const char* name) { // 添加构造函数
		this->name = name;
	}

	const char* get_name() {
		return this->name;
	}
	void display_info() {
		cout << "name:" << this->name << "\n";
	}
	void install_bullet(Bullet* bullet) {
		this->bullet = bullet;
		cout << this->name << " 已经安装子弹\n";
	}
};



class Person {
public:
	const char *name;
	Gun* gun;
	Bullet* bullet;

	Person(const char *name) {
		this->name = name;
	}

	void display_info() {
		cout << "name:" << this->name << "\n";
	}
	void get_gun(Gun* gun) {
		this->gun = gun;
		cout << this->name << " 拿起了" << gun->get_name() << "\n";
	}
	void get_bullet(Bullet *bullet) {
		this->bullet = bullet;
		cout << this->name << " 拿起了子弹,威力是:" << bullet->get_power() << "\n";
	}
	void install_bullet_to_gun() {
		this->gun->install_bullet(this->bullet);
	}

};

int main(){

	class Person hero("钢铁侠");
	hero.display_info();

	class Gun gun("AK47");
	gun.display_info();

	class Bullet bullet(10);
	bullet.display_info();

	hero.get_gun(&gun);

	hero.get_bullet(&bullet);

	hero.install_bullet_to_gun();

	return 0;
}

在这里插入图片描述
注意:
一开始Gun类的定义在Bullet类的定义之前,但是它使用了Bullet类。这会导致编译器无法识别Bullet类。我们需要提前声明Bullet类。
另外,确保所有指针变量在使用之前已经正确初始化。

标签:name,pStu,对象,age,C++,面向对象,理解,Student,cout
From: https://blog.csdn.net/qq_44114055/article/details/140825680

相关文章

  • Linux C++ 多线程编程
    LinuxC++多线程编程参考教程:c++:互斥锁/多线程的创建和unique_lock<mutex>的使用_mutex头文件vc++-CSDN博客1.编写unique_mutex1.1创建文件夹通过终端创建一个名为unique_mutex的文件夹以保存我们的VSCode项目,在/unique_mutex目录下打开vscode。rosnoetic@rosnoetic-Virt......
  • 时间分辨率、采样率与采样深度三者关系理解
    在脑成像研究中,分辨率和采样率是一个经常被提及的概念,但分辨率和采样率有时候容易混淆。除此之外,采样深度这个重要的概念却很少被提及。因此,本篇随笔主要内容是为阐述上述三者的概念以及相关联系。概念的明晰了解关系之前,首先需要明晰三者的定义概念,其中分辨率仅会说明时间分辨......
  • C++入门基础知识9
    C++中的分号&语句块在C++中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。例如,下面是三个不同的语句: 语句块是一组使用大括号括起来的按逻辑连接的语句。例如: C++不以行末作为结束符的标识,因此,您可以在一行上放置多个语句......
  • C++ call_once详解
    引言在多线程编程中,常常需要确保某些初始化操作只执行一次,例如初始化一个全局资源或单例模式中的实例创建。C++11引入了std::call_once和std::once_flag,为这种需求提供了便捷和高效的解决方案。一、基本概念1.std::call_oncestd::call_once是一个函数模板,它确保某个函数在......
  • C++11新特性
    C++11新特性语言特性移动语义右值引用转发引用可变模板列表初始化静态断言类型推导lambda表达式decltype类型声明nullptr空指针强类型枚举属性constexpr常量表达式委托构造用户定义语义显式虚重载Final限定符:限定的东西无法......
  • C++20新特性
    C++20新特性语言特性协程concept概念指定初始化器lambda表达式模板语义范围for循环增加初始化器[[likely]][unlikely]属性废弃隐式捕获this非类型模板参数的类类型constexpr虚函数explict(bool)立即函数usingenums,能直接进行using了lambda捕获参数包char8_t类型......
  • 第十章 面向对象编程
    10.1基本概念类:具有相同方法和属性的一类事物对象、实例:一个拥有具体属性值和动作的具体个体实例化:从一个类得到一个具体对象的过程10.2oop面向对象的程序开发#1.类的命名"""类的命名:推荐使用大驼峰命名法,每个单词的首字母都要大写mycar=>MyCar"""#2.......
  • 我敢说,很多硬件工程师和射频工程师没有真正理解有源器件和无源器件,三分钟钟带你吃透!
    在电子电路中,我们经常会遇到两种基本类型的器件:有源器件和无源器件。这两种器件在电路中的工作方式、能量来源以及功能特性上有着本质的区别。有源器件是指那些在工作时需要外部电源提供能量的器件。这类器件能够控制、放大或产生电能,常见的例子包括晶体管、集成电路、运算放......
  • visual studio code安装与C/C++语言运行
    VisualStudioCode(VSCode)安装与C/C++语言运行需要几个步骤,包括安装VSCode、配置C/C++环境以及安装必要的插件。以下是一个详细的步骤指南:1.安装VSCode访问官网:首先,前往VSCode的官方网站 VisualStudioCode-CodeEditing.Redefined 进行下载。下载并安装:选择......
  • Chapter 31 面向对象数据分析案例
    欢迎大家订阅【Python从入门到精通】专栏,一起探索Python的无限可能!本篇文章参考:黑马程序员【面向对象数据分析案例】某公司有两份数据文件:“2011年1月销售数据.txt”和“2011年2月销售数据JSON.txt”。前者是普通文本文件,使用逗号分隔数据记录,内容依次为日期、订单编......