• C++学习——坚持(二)


    前言

    努力不一定成功,但是坚持做好一件事一定很酷。

    在上一篇文章 C++学习——共勉(一) 中学习了C++语言的特点和程序结构,这篇文章就简单看看面向对象的基本概念。

    在这里插入图片描述

    一:结构化程序设计

    在面向对象程序设计方法出现之前,软件界流行的主流设计方法之一就是结构化程序设计方法,也称为面向对象的设计方法。
    在机构化程序设计中,采用自顶向下、逐步求精以及模块化思想,有个著名的公式体现了这一思想:数据结构+算法=程序。可以说,程序基本上都含有顺序、选择、循环3种基本控制结构。

    一个完整的c++程序包括以下几个部分:

    1. 一个主函数,可以用来调用其他函数,也叫做主程序(关于主函数是否能被调用,我在网上也查了一些资料并实验了一下:如果不加约束条件去调用主函数的话就会死循环,这时候考虑用递归的思想去调用就能运行出来。但是一般情况下不会对主函数进行调用,个人觉得c++中主函数能否被调用应该还未定义,期待前辈们指点!)
    2. 自主定义的任意多个类和全局函数
    3. 全局说明,在所有函数和类定义之外的变量说明和函数原型
    4. 必要注释
    5. 头文件

    对于比较大的文件,可以根据主函数和所定义的各个类以及全局函数的功能和相互关系,可以将类和全局函数划分为几个程序文件,包括 cpp. 文件(源程序文件)和 .h 文件(头文件)。

    1:面向对象的程序设计

    对象就是数据+函数,也就是属性+操作。举个简单的例子:员工的姓名、职位、工资等就是一个个变量;员工进行加班、出差、摸鱼划水,或者获得提拔、炒鱿鱼等就是操作;而操作会施加于属性,比如“加班、出差、摸鱼划水”操作会修改“工资”属性;“提拔、炒鱿鱼“操作会修改”职位“属性。
    用对象名标识一个个对象,用数据表示对象的属性,再用函数实现操作。
    C++中使用对象名、属性、操作三要素来描述对象。

    2:类模型结构

    类模型结构和对象结构很相似,它们都含有属性和操作,唯一不同的是对象结构图中有对象名而没有类名;类模型结构图中有类名但没有对象名。
    在这里插入图片描述在这里插入图片描述

    二:创建类对象的基本形式

    定义一个普通对象,即类变量的基本方法有两种:
    方法一

    类名 对象名;

    类名 对象名(参数);

    类名 对象名 = 类名(参数);

    可以扩展为对个对象:
    类名 对象名1,对象名2,....;
    或者
    类名 对象名 1(参数1),对象名2(参数2),...;

    方法二

    类名 *对象指针名 =new 类名; //使用该方法调用函数时,调用无参的构造函数,如果这个构造函数是由编译器为类提供的,那么类中成员变量不进行初始化。
    或者
    类名 *对象指针名 =new 类名(); //在创建对象时调用无参的构造函数。如果这个构造函数时由编辑器为类提供的,那么对类中的成员变量进行初始化。
    或者
    类名 *对象名指针 =new 类名(参数);
    使用new创建对象时返回的是一个对象指针,这个指针指向本类刚创建的这个对象。使用new 创建的对象,必须用delete撤销。

    声明对象引用(变量别名)格式:
    类名 &对象引用名=对象;

    声明对象指针格式:
    类名 *对象指针名=对象的地址;

    声明对象数组格式:
    类名 对象数组名[数组大小];

    例如,我们定义了一个类 A:

    A b1,c1;//定义A类的对象b1和c1
    A *p=&b1;//定义一个类型为A类的指针,指向对象b1
    A &Q=c1;//定义A类类型对象C1的引用Q
    A B[3];//定义A类类型对象的数组B,含有3个元素
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    三:类的初步知识

    1:类的定义

    面向对象方法中的类,是对具有相同属性中的同一类对象的抽象描述,其内部包括属性(本类的成员变量)和行为(本类的成员函数)两个主要部分,也就是类以数据为中心把相关的函数组成为一体。
    在C++中,类定义的一般格式:

       class 类名
       {
       访问范围说明符:
       成员变量 1
       成员变量 2
       ...
       成员函数声明 1
       成员函数声明 2
       ...
       访问范围说明符:
       更多成员变量
       更多成员函数变量
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    类以关键字 class 开始,后面是类名。类名的定义遵循一般的标识符命名规则,也就是字母、数字、下划线的组合并且对大小写敏感,但不能使用数字开头,也不能和系统中使用的关键字完全相同。
    类是具有唯一标识符的实体,就是说类名不能完全 重复,类的定义以“ ;” 结束,大括号中的部分叫做类体。

    “成员变量”是类中的一类成员,代表对象的属性,个数不限,也称为数据成员。成员变量的声明方式和普通变量的声明方式相同。“成员函数“是类中的另一类成员,代表对该类对象所含数据操作的方法,个数不限,其声明方式和普通函数的相同。
    成员变量和成员函数的出现次序没有限制,一个类的成员函数之可以相互调用,类中可以不含有任何成员变量和成员函数,这样的类叫做“空类”。
    成员函数既可以在类体内定义,也可以在类体外定义。如果成员函数定义在类体内部,则默认是内联函数
    如果成员函数定义在类体外,则类体内必须要有函数原型,类体外函数定义的前面要有限定,格式为:

    返回值类型 类名::成员函数名(参数列表)
    {
    成员函数的函数体
    }
    类名是成员函数所属类的名字, 符号 :: 是类作用域的运算符,表明它后面的成员函数是属于类名标识的这个类的。返回值类型就是这个成员函数返回值的类型。

    2:类成员的可访问范围

    访问范围说明符一共有三种 public(公有),private(私有),protect(保护),在类的定义中可以以任意的次序出现多次。

    public使用它修饰的类成员可以在程序任何地方被访问
    private使用它修饰的类成员仅能在本类中被访问
    protect使用它修饰的类成员能在本类内和子类中被访问

    成员的可访问范围由它之前离得最近的访问范围说明符决定,如果某个成员前面没有访问范围说明符,那么对于类来说,该成员默认为私有成员。

    	class A
    	{
    		int m,n;
    	public:
    		int a,b;//公有成员变量
    		int func1();//公有成员函数
    	private:
    		int c,d;//私有成员变量
    		void func2();//私有成员函数
    	public:
    		char e;//公有成员变量
    		int f;//公有成员变量
    		int func3();//公有成员函数
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    类成员访问示例

    #include 
    #include 
    using namespace std;
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    class Staff
    {
    	private://私有成员
    		string name;
    		int salary;
    	public://公有成员
    		void setName(string);
    		string getName();
    		void setSalary(int);
    		int getSalary();
    		int averageSalary(Staff);
    };
    	void Staff::setName(string myname)
    	{
    		name=myname;
    	}
    	string Staff::getName()
    	{
    		return name;
    	}
    	void Staff::setSalary(int mysalary)
    	{
    		salary=mysalary; 
    	}
    	int Staff::getSalary()
    	{
    		return salary;
    	}
    	int Staff::averageSalary(Staff s1)
    	{
    		return (salary+s1.getSalary())/2;
    	}
    int main(int argc, char** argv) {
    	Staff sL,sS;
    	sL.setName("Linda");//name 是私有变量,不能直接访问,需要通过公有成员setName来访问
    	sL.setSalary(12345);//salary 也是私有变量,需要借助公有成员 setSalary来访问
    	cout<<"第一个员工的姓名和薪水是:"<<sL.getName()<<","<<sL.getSalary()<<endl;
    	sS.setName("Susan");
    	sS.setSalary(54321);
    	cout<<"第二个员工的姓名和薪水是:"<<sS.getName()<<","<<sS.getSalary()<<endl;
    	cout<<"两个员工的平均薪水是:"<<sL.averageSalary(sS)<<endl; 
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    输出结果:
    在这里插入图片描述

    3: 类的定义示例

    //定义一个日期类myDate
    class myDate
    {
    public:
    	myDate();//构造函数 
    	myDate(int,int,int);//构造函数 
    	void setDate(int,int,int);//设置日期 
    	void setDate(myDate);//设置日期 
    	myDate getDate();//获取日期 
    	void setYear(int);//设置年 
    	int getMonth();//获取月 
    	void printDate() const;//打印日期  成员函数printDate()需要使用const进行限定
    private:
    	int year,month,day;//成员变量,表示年,月,日 
    };  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    //在类体外定义成员函数
    	myDate::myDate()
    	{ year=2022,month=1,day=1;
    	}//构造函数
    	myDate::myDate(int y,int m,int d)
    	{	year=y;month=m;day=d;
    	}//构造函数
    	void myDate::setDate(int y,int m,int d)
    	{	year=y;month=m;day=d;
    	 	return;
    	}//设置日期
    	void myDate::setDate(myDate oneD)
    	{	year=oneD.year;month=oneD.month;day=oneD.day;
    	 return;
    	}//设置日期
    	myDate myDate::getDate()
    	{	return*this;
    	}//获取日期;*this是自身对象
    	void myDate::setYear(int y)
    	{	year=y;
    		return;
    	}//设置年
    	int myDate::getMonth()
    	{	return month;
    	}//设置月
    	void myDate::printDate()const
    	{  cout<<year<<"/"<<month<<"/"<<day;
    	 return;
    	}//打印日期
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在myDate 类中定义了分别表示年、月、日的三个私有成员变量来访问year、month、day,并且定义了公有的访问成员函数,可用于访问这些成员变量。

    setDate()是重载函数,使用不同类型的量设置一个日期。getDate()用于获取函数。通常设置函数以set 为函数名前缀,获取函数以 get 为函数名前缀。
    在C++语言中,当调用一个成员函数时,系统自动向它传递一个隐含的参数,这个参数是一个指向调用该函数的对象的指针,叫做 this 指针,从而使成员函数知道对哪个对象进行操作。在程序中,可以使用关键字 this 来引用该指针。例如:如果在A类中有成员变量 date 和成员函数 getDate(),通过类A的对象a 调用函数 getDate(),那么编译系统就会把对象a 的地址赋值给函数getDate()中的this 指针,this 指针访问到的成员变量 date 就是属于对象a 的成员变量,也就是 this->date 就相当与a.date

    //定义一个学生类Student
    class Student
    {
    public:
    		void setStudent(string,myDate);//设置学生信息
    		void setName(string);//设置姓名
    		string getName();//获取姓名
    		void setBirthday(myDate);//设置生日
    		myDate getBirthday();//获取生日
      	    void printStudent() const;//打印信息 
    private:
    		string name;
    		myDate birthday;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    //在类体外定义成员函数
    	void Student::setStudent(string s,myDate d)
    	{	 name=s;
    		 birthday.setDate(d);
    		 return;
    	 }
    	 void Student::setName(string n)
    	 {	 name=n;
    	 	 return;
    	 }
    	 string Student::getName()
    	 {	 return name;
    	 }
    	 void Student::setBirthday(myDate d)
    	 { 	birthday.setDate(d);
    	  	return;
    	  }
    	  myDate Student::getBirthday()
    	  {	 return birthday;
    	  }
    	 void Student::printStudent() const
    	 {	cout<<"姓名"<<name<<"/"<<"\t 生日";
    		birthday.printDate();//调用类myDate 的成员函数
    	 	cout<<endl; 
    	 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    定义类时,类的成员变量的类型不仅可以是系统内置的基本数据类型,还可以是类类型:定义学生类Student ,它包含姓名,生日,专业等属性,姓名可以用系统定义好的类string来表示生日可以用 定义好的类myDate 来表示。

    在这里插入图片描述

    四:访问对象的成员

    1:使用对象访问成员变量与调用成员函数

    定义了类和对象后就可以访问对象的成员。通过对象访问成员变量的一般格式:

    对象名.成员变量名

    调用成员函数的一般格式:

    对象名.成员函数名(参数表)

    程序举例

    验证Student 类功能的驱动程序

    #include 
    #include  
    #include "myDate.h"
    #include "Student.h"
    using namespace std; 
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    
    int main(int argc, char** argv) {
    	Student ss;
    	int y,m,d;
    	string name_;
    	cout<<"请输入学生的姓名和生日" <<endl;
    	cin>>name_>>y>>m>>d;
    	ss.setStudent(name_,myDate(y,m,d));//创建Student的对象 ss,这里要考虑到成员名的访问范围,需要通过类Student 提供的公有访问方法即setStudent()才能将键盘读入的字符串赋值给对象ss。
    	ss.printStudent();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    输出结果:
    在这里插入图片描述

    2:使用指针访问对象的成员

    我们将程序主函数修改一下:

    int main()
    { 	Student ss;
    		int y,m,d;
    		string name_;
    		Student *st=&ss;//指针st,指向ss,并使用&ss给指针赋初值
    		cout<<"请输入学生的姓名和生日";
    		cin>>name_>>y>>m>>d;
    		st->setStudent(name_,myDate(y,m,d));//指针操作符  指针名->成员名
    		st->printStudent();
    		return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3:使用引用访问对象的成员

    int main()
    {
    	Student ss;
    	int y,m,d;
    	string name_;
    	Student &sn=ss;//ss的别名sn,sn和ss成为同一个对象的不同名字
    	cout<<"请输入学生的姓名和生日";
    	cin>>name_>>y>>m>>d;
    	sn.setStudent(name_,myDate(y,m,d));//访问成员时采用点操作符 引用名.成员名
    	sn.printStudent();
    	return 0;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    五:标识符的作用域与可见性

    每个标识符都有各自的作用域(指的是标识符的有效范围,也就是它在程序中的存在区域)和可见性(是指在程序中的哪个区域里可以使用),对于同一个标识符来说,这两个区域可能是不完全重合的。类名、函数名、变量名等都是标识符。
    c++中的标识符的作用域有函数原型作用域、局部作用域(块作用域)、类作用域和命名空间作用域。

    1:函数原型作用域

    在声明函数时原型时形参的作用范围就是函数原型作用域,这是c++程序中最小的作用域,生命周期最短:

    double area(double d)
    d为参数,作用域是原型作用域,即标识符d的作用范围在函数 area 形参列表的左右括号之间,在程序的其他地方不能应用这个标识符。

    函数原型作用域的作用范围就在括号中

    2:局部作用域

    程序中使用相匹配的一对大括号括起来的一段程序叫做块。作用域局限在块内的叫做局部作用域:
    在这里插入图片描述

    3:类作用域

    类可以被看作是一组有名字的成员的集合,类X的成员m具有类作用域,对m的访问方式有:
    如果在类X 的成员函数中没有声明同名的局部作用域标识符,就可以在该函数内直接访问成员m;
    在类外,可以通过表达式x.m或X::m进行访问;还可以通过ptr->来访问,其中ptr是指向类X的一个对象的指针

    4:命名空间作用域

    命名空间是为了消除同名引起的歧义,具有命名空间作用域的变量也叫做全局变量。定义命名空间的一般格式:

    namespace 命名空间名
    {
    	命名空间内的各种声明(函数声明等)
    }
    
    • 1
    • 2
    • 3
    • 4

    c++标准库中所有的标识符都定义在一个名为std 的命名空间中,因此在程序的示例部分中都出现了:using namespace std;

    在这里插入图片描述

    总结

    当我们在实施自己的计划,追求自己的理想时,如果能够坚持下去,再坚持下去,或许我们在年老甚或离开人世的时候,会少一些遗憾。
    在这里插入图片描述

    如有不足,还请指正,感谢!

  • 相关阅读:
    2023NOIP A层联测18 划分
    【贪心算法】背包问题
    [ubuntu系统下的文本编辑器nano,vim,gedit,文件使用,以及版本更新问题]
    SPOOL、SQLLOADER数据导出导入的一点小总结
    5G面试题目和答案,计算机面试
    C语言 驼峰命名法和下划线命名法
    Android12 OTA编译差分包报错问题
    Java ~ Executor ~ ScheduledExecutorService【总结】
    基于RTSP协议的实时视频流传输的源码分析
    node封装一个图片拼接插件
  • 原文地址:https://blog.csdn.net/weixin_64122448/article/details/125768521