面向过程和面向对象的主要区别在于它们处理问题的方式和关注点不同,面向过程更注重问题的解决步骤和操作,而面向对象更注重问题的抽象和模块化
在面向过程的编程中,数据和函数之间的联系较弱,而在面向对象的编程中,数据和函数被封装在一起,形成了具有完整属性和行为的对象
此外,面向对象编程还提供了封装、继承和多态等特性,使得代码更加易于维护和扩展
面向过程编程将程序视为一系列的过程或函数的集合,程序的执行流程主要由函数的调用和控制流语句组成,强调问题解决过程中对步骤和操作的关注,通过按照特定顺序依次执行一系列函数来完成任务
①程序以过程或函数为单位进行组织和实现
②强调顺序性和线性执行,即按照特定的顺序执行一系列的函数
③数据和函数之间的联系较弱,函数通常使用全局变量或参数传递数据
④适用于简单的、直接的问题和算法,它注重解决问题的步骤和操作,对于程序的结构相对简单的情况下,可以提供较好的性能和效率
面向对象编程将程序设计建立在对象的概念上,程序被组织为一组相互协作的对象,这些对象通过消息传递来进行交互和处理,主要思想包括封装、继承和多态等核心概念
对象是对现实世界中某个具体或抽象事物的抽象表示,每个对象都具有状态和行为
①封装:将对象的状态和行为封装在一起,通过限制对内部数据和方法的直接访问,提供了更好的安全性和灵活性
②继承:通过继承机制,一个类可以派生出子类,从而继承父类的属性和方法。继承促进了代码重用和扩展,使得代码更易于维护和扩展
③多态:多态允许不同的对象对同一个消息做出不同的响应。通过多态,可以编写出更通用、灵活和可扩展的代码
④面向对象编程具有很多优点,包括可重用性、可维护性、抽象和模块化等
在C语言中结构体只能定义变量,在C++中,结构体内不仅可以定义变量,还能定义函数
在C语言中的结构体为struct,但C++更喜欢用class,关于这个的原因,我们后面会讲到,它们两个定义还是有区别的
class name
{
//...
};
定义方式与结构体相同,花括号中间是成员 class为类的关键字,name为类的名字,花括号中为类的主体,还有后边的分号
类体中的内容叫类的成员:类中的变量叫做类的属性或成员变量,类中的函数称为类的方法或者成员函数
类的两种定义方式: 1、声明和定义全都放在类体中,但是成员函数如果在类中定义,编译器可能会将其当做内联函数处理 2、类声明放在.h文件中,成员函数定义放在.cpp文件中,成员函数名前要加类名 我们建议使用第二种,这样就不会出现问题
C++实现封装的方式是用类将对象属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
开始时我们只使用public与private来修饰: (1)public修饰的成员在类外可以直接被访问 (2)private修饰的成员在类外不能直接被访问,在类内可以直接访问 (3)访问权限作用域从该访问限定符出现的位置到下一个访问限定符的位置或者 } 的位置 (4)class的默认访问权限是private,struct为public
访问限定符只有在编译时有用,用于规范代码,在运行时没有区别
关于第(4)条,因为C++要兼容C语言,所以struct在C++中既可以做结构体又可以定义类
封装就是将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互,也就是说,过程性的代码封装到函数中,在外部只能调用函数而不调用和改变其中的参数
类定义了一个新的作用域,花括号以内的就叫域
在类体外定义成员时需要使用作用域操作符::指明成员属于哪个类域
类内:
class Person
{
public:
void Print()
{
cout << name << " " << gender << " " << age << endl;
}
private:
char name[20];
char gender[3];
int age;
};
类外:
class Person
{
public:
void Print();
private:
char name[20];
char gender[3];
int age;
};
// 这里需要指定Print是属于Person这个类域
void Person::Print()
{
cout << name << " " << gender << " " << age << endl;
}
用类类型创建对象的过程叫做类的实例化
类是对对象进行描述的,限定了类有哪些成员,定义一个类并没有分配实际内存空间来存储它,当实例化后,才开辟实际的物理空间,存储类成员变量,在实例化之前不占用任何空间
class Person
{
public:
void Print();
private:
char a;
int b;
};
void Person::Print()
{
cout << sizeof(Person)<< endl;
}
int main()
{
Person person;
person.Print();
return 0;
}
我们在前边提到过,class与struct结构相似,所以class也有内存对齐的性质,有关内存对齐的内容在这一篇博文中有所讲解,所以我们的出结论:类中的函数可能不占用内存
类对象在内存中的存储方式如下图,类成员函数存放在公共代码区,因为每次调用的类成员函数都是同一个函数,没必要再分到各个对象中,而每个对象中的成员变量可能不同,所以它们都分别存好
class Person
{
public:
void Print();
void Person::Print()
{
cout << sizeof(Person)<< endl;
}
由上述代码以及运行结果得出,如果类中之后类成员函数,那么它们会在内存中开辟一块1字节的空间,这块空间主要是为了能够调用函数,而不是类成员函数需要空间
我们先来看一个程序,从中找出需要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;
};
这是一个日期类,我们看到初始化的类成员函数前加了_来和形参进行区分,这样会搞的很难受,在C++中引入this来解决这个问题,C++编译器给每个非静态的成员函数增加了一个隐藏的指针参数,让该指针指向当前对象,在函数体中所有“成员变量”的操作,都是通过该指针去访问,但用户不需要传递,由编译器自己完成
this指针是* const型的指针,即int* const、char* const等,所以成员函数中不能给this指针赋值
this指针只能在成员函数内部使用,每个成员函数的this不一样,可能他们的指向一样,但它们都是在某成员函数的内部
this指针本质上是成员函数的形参,对象中不存储this指针,当对象调用函数时,将对象地址作为实参传递给this形参
this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户自己传递
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}//this自动加入,不写this->也可以
private:
int _year;
int _month;
int _day;
};
this指针不存在于内存中某一特定区域,因为它在函数当中,所以在使用时会创建在栈中
this指针不可以为空,因为空指针不能解引用,但如果不涉及解引用操作,如下程序
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
这里转到汇编代码发现程序并没有对p指针进行解引用,进入函数Print后也没有对this指针解引用,所以程序会正常运行
如果将程序稍加改动
class A
{
public:
void Print()
{
cout << _a << endl;//这里访问到内部成员,需要解引用
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
这里我们明显可以看出对指针this进行了解引用,而this就是p指针,p指针为空,不能够解引用,所以程序不能运行
C++实现栈是学习C++类的一个很重要的步骤,他能够让我们看清C语言与C++之间的差异,这里有C语言实现的栈
C++中通过类可以将数据以及操作数据的方法进行完美结合,通过访问权限可以控制那些方法在类外可以被调用,即封装,即C++中参数是编译器维护的,C语言要用户自己维护
class Stack
{
public://公共访问,但在类中可以访问private的内容,只是在类外不能直接访问
void Init()
{
a = nullptr;
top = capacity = 0;
}
void Push(int x)
{
if (top == capacity)
{
int newcapacity = capacity == 0 ? 4 : capacity * 2;
int* tmp = (int*)realloc(a, sizeof(int) * newcapacity);
if (tmp == nullptr)
{
perror("realloc fail");
exit(-1);
}
a = tmp;
capacity = newcapacity;
}
a[top++] = x;
}
void Pop()
{
top--;
}
int Top()
{
return a[top - 1];
}
bool Empty()
{
return top == 0;
}
void Destroy()
{
free(a);
a = nullptr;
capacity = top = 0;
}
private://隐私访问
int* a;
int top;
int capacity;
};
int main()
{
Stack st;
st.Init();//使用类函数的方式就是.加函数名
cout << st.Empty() << endl;
st.Push(1);
st.Push(2);
st.Push(3);
st.Push(4);
cout << st.Empty() << endl;
cout << st.Top() << endl;
st.Pop();
cout << st.Top() << endl;
st.Destroy();
return 0;
}
和C是一个写法的代码我就不添加注释了 和C语言相比C++更加简洁,而且使用的接口也更加容易理解
现在对于面向对象和面向过程这两个编程方法应该有一定的了解了,因为我们的目标用户可能不懂C语言,这样一来使用C语言的程序目标用户没办法维护,但经C++封装的类只需要提供接口,举个例子,比如计算器中的加法,对于C++来说我只要提供一个加法的接口,然后输入两个数字就可以得出答案,但对于C语言来说,我需要整个程序,不然我不知道如何使用,这就是它们的差别,也是面向对象编程思想必须出现的原因
今日分享就到这了~