0. 面向过程程序设计和面向对象程序设计的区别
面向对象程序设计往往关注的是怎么去做,是将解决问题的步骤分析出来,然后用函数把步骤一步一步实现,然后再依次调用就可以了。而面向对象是将构成问题的事物,分解成若干个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在解决问题过程中的行为。
因此我们之前讲到过的C语言是面向过程的,关注的是过程,分析出求解问题的步骤。而C++是面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
面向对象的特点:封装、继承、多态。
封装性:就是把属性和方法都放在一个类里面,而且还可以通过访问类的权限属性给区分 开,更加安全,不想要释放的功能,直接搞成私有机制。
继承性:就是把之前已经实现好的代码或者方法通过继承的方法拿过来使用,能节省大量的代码量,符合代码设计里面的继承优秀代码特性。
多态性:由于可以继承多个类,能够组合成多种特性,但多态的关键是覆盖,就是同一个方法可以用不同的方式去实现,展现出多态性。
以上的特点我们会在后续详细解释到。
1. C++类的引入
了解c++,首先要了解类和对象,c++ 中的类可以看成c语言中的结构体的升级版,C 语言结构体是一种构造类型,可以包含若干个成员变量,成员变量的类型可以不同。在C++中,结构体内不仅可以定义变量,也可以定义函数。
C++中class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分 号不能省略。 类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者 成员函数。下面请看代码:
#include<iostream>
using namespace std;
struct student
{
int age;
};
class student1
{
public:
void print()//成员函数,方法
{
cout <<"年龄:" << age << endl;
}
int age; //成员变量,属性
private:
int tele;
};
int main()
{
student s1;
s1.age = 18;
student1 s2;//创建对象
s2.age = 20;
s2.print();
return 0;
}
关于class(类)的几点说明:
(1)类的定义的最后有一个分号,它是类的一部分,表示类定义结束,不能省略。
(2)一个类可以创建多个对象,每个对象都是一个变量
(3)类是一种构造类型,大小的计算方法和 struct 一样,需要字节对齐
(4)类成员变量的访问方法:通过 . 或者 -> 来访问
(5)成员函数是类的一个成员,出现在类中,作用范围由类来决定,而普通函数是独立的,作用范围是全局或者某个命名空间。
代码中的 public 和 private 为类的访问控制,除此之外还有一个 protected,三个的说明如下:
(1) public 修饰的成员在类外可以直接被访问
(2)protected 和 private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
(3)访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
(4)如果后面没有访问限定符,作用域就到 } 即类结束。
(5)class的默认访问权限为private,struct为public(因为struct要兼容C)
(6)访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别。
C++中struct 和 class 的区别:
C++ 需要兼容 C 语言,所以 C++ 中 struct 可以当成结构体使用。另外 C++ 中 struct 还可以用来 定义类。和 class 定义类是一样的,区别是 struct 定义的类默认访问权限是 public,class定义的类默认访问权限是 private。
类的另一种定义方式:声明放在头文件当中,成员函数定义放在.cpp文件中,成员函数名前需要加类名 :: 。
// .h
struct student
{
int age;
};
class student1
{
public:
void print();
int age;
private:
int tele;
};
// .cpp
void student1::print()
{
cout <<"年龄:" << age << endl;
}
3. this指针
先看代码:
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 main()
{
Date d1, d2;
d1.Init(2023,3,12);
d2.Init(2023,3,13);
d1.Print();
d2.Print();
return 0;
}
有这样的一个问题: Date 类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函 数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编 译器自动完成。
void print()
{
cout << _data << endl;
}
//编译处理包含this指针
void print(Data* this)
{
cout << this->_data << endl;
}
this指针的特性
(1) this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
(2)只能在“成员函数”的内部使用
(3)this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针
(4)this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传 递,不需要用户传递。
4.构造函数和析构函数
在c++中,由一种特殊的成员函数,名字和类名相同,没有返回值,不需要用户显示调用(用户也不能调用),而是在创建对象的时候自动调用。 这种函数我们称为构造函数;和普通函数一样,构造函数是允许重载的,一个类可以有多个重载的构造函数,在创建对象时根据传递实参来判断调用哪一个构造函数。
(1)函数名必须和类型相同
(2)不能有返回值,函数体不能有return语句
(3)构造函数在定义对象时会自动调用,不需要手动调用
创建对象时系统会调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数进行清理工作,如释放分配的内存、关闭打开的文件等,这个函数就是析构函数。析构函数没有参数,不能被重载,一个类只能有一个析构函数,如果用户没有定义析构函数,编译器会提供默认的析构函数。
class Array
{
private:
int *m_data; //数组的起始地址
int m_size;
public:
Array(); //无参构造函数,函数名和类名一致,没有返回值
Array(int s); //有参构造函数
Array(int s,int z); //有两个参数的构造函数
~Array(); //析构函数,函数名为:~类名 ,没有返回值,没有参数
};
Array::Array()
{
cout<<"Array的无参构造函数"<<endl;
m_size = 5;
m_data = (int *)malloc(sizeof(int) *m_size);
}
Array::Array(int s) //有参构造函数
{
cout<<"Array的有一个参数的构造函数"<<endl;
m_size = s;
m_data = (int *)malloc(sizeof(int) * m_size);
}
Array::Array(int s,int z) //有两个参数的构造函数
{
cout<<"Array的有两个参数的构造函数"<<endl;
m_size = s;
m_data = (int *)malloc(sizeof(int) * m_size);
}
Array::~Array()
{
cout<<"Array的析构函数"<<endl;
if(m_data != NULL)
{
free(m_data);
m_data = NULL;
}
}
Array a1; //创建对象,会自动调用构造函数