C++深入讲解类与对象之OOP面向对象编程与封装

目录
  • 1.面向对象编程
  • 2.面向过程性编程和面向对象编程
  • 3.类的引入
  • 4.类的定义
    • 4.1类的两种定义方式
      • 4.1.1声明和定义全部放在类体中
      • 4.2.2.声明和定义不放在类体中
  • 5.类的访问限定符及封装
    • 5.1 访问限定符
    • 5.2封装
  • 6.类的作用域
  • 7.类的实例化
  • 8.类对象模型
    • 如何计算类对象的大小

面向过程编程也叫结构化编程。虽然结构化编程的理念提高了程序的清晰度,可靠性,并且方便维护。但它再编写大型的程序时,仍然面临这巨大的挑战,OOP(面向对象编程)提供了一种新的方法。与强调算法的过程性编程不同的是,OOP强调的是数据。--引自《C++ Primer Plus(第六版)》

1.面向对象编程

C++ 是 基于面向对象 的, 关注 的是 对象 ,将一件事情拆分成不同的对象,靠对象之间的交互完成。

在C++中,类是一种规范,它描述了这种新型数据格式,对象是根据这种规范构造的特定数据结构。这里有小伙伴会问,类是什么?这个问题会在(3.类的引入) 中重点介绍。

2.面向过程性编程和面向对象编程

通过下面这个例子,可以更加清晰的揭示OOP的观点和过程性编程的差别。

此举例改变自《C++ Primer Plus(第六版)》:

曼联足球俱乐部的一名新成员被要求记录球队的统计数据。很自然他会借助计算机来完成这项任务。

如果这个新成员是过程性程序员,可能会这样考虑:

我要输入每名运动员的姓名,进球数,助攻数,登场数等其他重要的基本统计数据。之所以使用计算机,是为了简化统计工作,因此让他来计算某些数据。另外,我还希望程序能够显示这些结果。应该如何组织呢?我让main()调用一个函数来获取输入,调用另外一个函数来进行计算,然后调用第三个函数来显示结果。那么,获得下一场比赛的数据后,又改怎么做呢?当然不想从头开始,可以添加一个函数来更新统计数据。可能需要在main函数中添加一个菜单,选择是输入,计算,更新还是显示数据等。则如何表示这些数据呢。可以使用一个字符串来存储选手的姓名,用另外一个数组来存储每位球员的进球数,再用一个数组存储助攻数等等。这种方法太不灵活了。因此可以设计一个结构体来存储每位球员的所有信息,然后用这种结构组成的数组来表示整个球队。

总之,采用过程性编程时,首先要考虑遵守的步骤,然后考虑如何表示这些数据。

如果换成一个OOP程序员,又将如何考虑呢?

首先要考虑数据——不仅要考虑如何表示数据,还要考虑如何使用数据:

OOP程序员会想,我要跟踪的是什么?当然是球员。因此要有一个对象表示整个球员的各个方面(不仅仅是进球数或助攻数)。因此这将是基本数据单元——一个表示球员的姓名和统计数据的对象。我需要一些处理该对象的方法。首先需要一种将基本信息加入到该单元中的方法;其次,计算机应计算一些东西,如进球率。因此要添加一些执行计算的方法。程序应自动完成这些计算,而无需用户的干扰。另外,还需要一些更新和显示信息的方法。所以,用户与数据交互的方式有三种:初始化,更新和报告——这就是用户接口。

总之,采用OOP方法时,首先从用户的角度考虑对象——描述对象所需的数据以及描述用户与数据交互所需的操作。完成对接口的描述之后,需要确定如何实现接口和数据存储。最后,使用寻得设计方案创建出程序。

3.类的引入

在过程化编程中我们用结构体来描述一个复杂对象(这里用C语言举例)。在C语言中,结构体中只能定义变量。结构体关键字是struct。在C++中,结构体内不仅可以定义变量,还可以定义函数

struct Student
{
	void SetStudentInfo(const char* name, const char* gender, int age)
	{
		strcpy(_name, name);
		strcpy(_gender, gender);
		_age = age;
	}
	void PrintStudentInfo()
	{
		cout << _name << " " << _gender << " " << _age << endl;
	}
	char _name[20];
	char _gender[3];
	int _age;
};
int main()
{
 Student s;
 s.SetStudentInfo("Peter", "男", 18);
 return 0;
}

上面结构体的定义, 在 C++ 中更喜欢用 class 来代替

4.类的定义

class className
{
    // 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号

class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号。

类中的元素称为类的成员:类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数。

4.1类的两种定义方式

4.1.1声明和定义全部放在类体中

需要注意:成员函数如果在类中定义 ,编译器可能会将其当成 内联函数 处理。

class Student
{
public:
	void SetStudentInfo(const char* name, const char* gender, int age)
	{
		strcpy(_name, name);
		strcpy(_gender, gender);
		_age = age;
	}
	void PrintStudentInfo()
	{
		cout << _name << " " << _gender << " " << _age << endl;
	}
public:
	char _name[20];
	char _gender[3];
	int _age;
};

4.2.2.声明和定义不放在类体中

声明放在.h文件中,类的定义放在.cpp文件中

//student.h
//学生
class Student
{
public:
	void SetStudentInfo(const char* name, const char* gender, int age);
	void PrintStudentInfo();
public:
	char _name[20];
	char _gender[3];
	int _age;
};
//test.cpp
#include "student.h"
void Student::SetStudentInfo(const char* name, const char* gender, int age)
{
	strcpy(_name, name);
	strcpy(_gender, gender);
	_age = age;
}
void Student::PrintStudentInfo()
{
	cout << _name << " " << _gender << " " << _age << endl;
}

一般情况下,更期望采用第二种方式。

5.类的访问限定符及封装

5.1 访问限定符

在刚刚的代码中,细心的小伙伴可以发现在类中出现了public这个词,那这到底有什么用呢?这就是我们现在要说明的访问限定符。在C++中,除了public(公有)外,还有private(私有),protected(保护)限定符。

那么为什么要引入访问限定符呢?

C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。

那么他们都有什么含义呢?

【访问限定符说明】

1. public修饰的成员在类外可以直接被访问

2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)

3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止

4. class的默认访问权限为private,struct为public(因为struct要兼容C)

注意:

1.访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别。

2.C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。和class是定义类是一样的,区别是struct的成员默认访问方式是public,class是的成员默认访问方式是private。

5.2封装

什么是封装?

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。封装的本质是一种管理。 我们使用类数据和方法都封装到一下。 不想给别人看到的,我们使用 protected/private 把成员 封装 起来。 开放 一些共有的成员函数对成员合理的访 问。所以封装本质是一种管理。

在C语言中,大多数情况中调用者和定义结构者不是同一个人,就可能会存在调用者测出bug的可能。

//C语言中数据和方法是分离的
struct Stack
{
	int* _a;
	int _top;
	int _capacity;
};
void StackInit(struct Stack* ps)
{
	assert(ps);
	ps->_a = NULL;
	ps->_capacity = 0;
	ps->_top = 0;
}
void StackPush(struct Stack* ps, int x)
{
}
struct Stack StackTop(struct Stack* ps)
{
}
int main()
{
	struct Stack st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	printf("%d\n", StackTop(&st));
	printf("%d\n", st._a[st._top]);     //可能就存在误用
	printf("%d\n", st._a[st._top - 1]); //可能就存在误用
}

这是我们在数据结构阶段用C语言实现的一个栈,在主函数中,我们想要访问栈顶的元素。在常规情况下,我们调用StackTop函数即可访问到栈顶元素。但是我们也可以使用访问数组下标的方式拿到栈顶元素,此时如果调用者不清楚使用者的定义方式,就有可能存在误用。例如:这段代码我们定义_top是栈顶元素的下一个元素的下标,因此栈顶元素的下标应该是_top-1,而调用者如果误以为top就是栈顶元素的下标,即有可能存在误用。因此这里太过自由。

为了解决这一问题,在C++中,结构体不仅可以定义变量,还可以定义函数。我们如果把函数定义在类中,我们把成员变量封装在类中,外界函数无法调用。因此如果此时我们想调用栈顶元素,我们只能调用Top函数的接口。这就避免了上述问题的发生。

class Stack
{
private:
	void Checkcapacity()
	{
	}
public:
	void Init()
	{
	}
	void Push(int x)
	{
	}
	void Top()
	{
	}
private:
	int* _a;
	int _top;
	int _capacity;
};

6.类的作用域

类定义了一个新的作用域 ,类的所有成员都在类的作用域中 。 在类体外定义成员,需要使用 :: 作用域解析符指明成员属于哪个类域。 就像在这段代码中,我们想要在类作用域外定义成员,就要使用::

7.类的实例化

用类类型创建对象的过程,称为类的实例化

1. 类只是 一个 模型 一样的东西,限定了类有哪些成员,定义出一个类 并没有分配实际的内存空间 来存储它

2. 一个类可以实例化出多个对象, 实例化出的对象 占用实际的物理空间,存储类成员变量

3. 做个比方。 类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图 ,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间

我们继续引用我们刚刚用C++所写的栈,其中st就是一个实例化对象。

class Stack
{
private:
	void Checkcapacity()
	{
	}
public:
	void Init()
	{
	}
	void Push(int x)
	{
	}
	void Top()
	{
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
int main()
{
	Stack st;
	st.Init();
	st.Push(1);
	st.Top();
	return 0;
}

8.类对象模型

如何计算类对象的大小

在C语言中,我们在学习结构体的时候知道,由于结构体中只定义变量,因此我们是可以计算出结构体的大小的。sizeof计算的是定义类型对象的大小。

那在C++中,由于类中不仅定义变量,还定义函数,那么类的大小是怎么计算的呢?

我们发现此类的大小还是12。

因此我们猜测:类对象的存储方式只保存成员变量,成员函数存放在公共的代码段。

那我们思考为什么采用这种方式呢?

在上述中说到,类就像是一份建筑图纸,而所建造的每一个房子中的name,capacity,top应当是不一样的。但是所调用的方法Init(),Top()应当是同一个方法。因此没有必要把函数在对象中存一份。我们也可以通过汇编看看不同的对象是否调用同一个函数。

我们能够发现st1和st2所调用得Init()函数是同一份。因此如果都把函数存在类中,就会造成浪费。因此我们可以把函数放在一个公共的区域,这个区域叫做代码段。

结论:一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。注意:最小内存单元是1.操作系统规定都要有地址记录,就像sizeof(void) = 1。

到此这篇关于C++深入讲解类与对象之OOP面向对象编程与封装的文章就介绍到这了,更多相关C++类与对象内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++进一步认识类与对象

    目录 赋值操作符重载函数 1.运算符重载 2.赋值运算符重载 3.默认的赋值操作符重载函数 4.赋值重载函数与拷贝构造函数的对比 日期类的实现 const成员 1.const修饰类的成员函数 2.小结 取地址及const取地址操作符重载函数 总结 赋值操作符重载函数 1.运算符重载 C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似. 其函数名为: operator + 需要重载的运算符符

  • C++中的类与对象深度解析

    目录 初始化列表 引论 初始化列表 explicit关键字 引论 explicit关键字使用 static成员 友元 引论 友元 内部类 基础概念 内部类的使用 补充 析构顺序例题 总结 初始化列表 引论 //初始化列表的引出 class B { public: B() { cout << "我是B的构造函数" << endl; } private: int _b; }; class A { public: A() { cout << "我

  • C++类和对象之多态详解

    目录 多态基本概念和原理剖析 多态案例1 计算器类 纯虚函数和抽象类 多态案例2 制作饮品 虚析构和纯虚析构 多态案例3 电脑组装 多态基本概念和原理剖析 多态:多态是C++面向对象的三大特性之一.多态分为静态多态和动态多态. 静态多态:函数重载和运算符重载属于静态多态,复用函数名. 动态多态:派生类和虚函数实现运行时多态. 区别: 静态多态的函数地址早绑定,编译阶段确定函数地址. 动态多态的函数地址晚绑定,运行阶段确定函数地址. #include <iostream> using names

  • C++类和对象之封装详解

    目录 封装的意义以及示例 访问权限 公共权限 public 保护权限 protected 私有权限 private struct 和 class的区别 成员属性私有化 案例1:设计立方体类 案例2:点和圆的关系 总结 封装的意义以及示例 封装是C++面向对象三大特征之一 封装的意义: 将属性和行为作为一个整体,表现生活中的事物将属性和行为加以权限控制 语法:class 类名{  访问权限 : 属性  /  行为 }: 类的对象的公共数据成员可以使用直接成员访问运算符 . 来访问. 示例1: 设计

  • C++函数指针+对象指针+this指针+指向类静态和非静态成员的指针

    目录 1.指向函数的指针 2.对象指针 3.this指针 4.指向类的非静态成员的指针 5.指向类的静态成员的指针 1.指向函数的指针 函数的代码在内存中的首地址,是由函数名表示的,也就是说函数名等价于函数代码首地址.因此,可以定义一个指向函数的指针,即函数指针.函数指针定义和赋值的语法如下,其中数据类型代表指向函数的返回类型,形参表为指向函数的形参表:赋值时必须保证指向的函数名和函数指针的返回类型和形参完全相同: 数据类型 (*函数指针名)(形参表);函数指针名 = 函数名; 下面的例子定义了

  • C++内核对象封装单实例启动程序的类

    复制代码 代码如下: //File Name: Singleton.h#pragma once class Singleton{private:    CString strGUID;    CString strMapFileGUID; HANDLE m_hSingleton; public:    Singleton();    ~Singleton();public:    void AppStart (const HWND & hWnd) const;}; 复制代码 代码如下: //Fi

  • C++深入讲解类与对象之OOP面向对象编程与封装

    目录 1.面向对象编程 2.面向过程性编程和面向对象编程 3.类的引入 4.类的定义 4.1类的两种定义方式 4.1.1声明和定义全部放在类体中 4.2.2.声明和定义不放在类体中 5.类的访问限定符及封装 5.1 访问限定符 5.2封装 6.类的作用域 7.类的实例化 8.类对象模型 如何计算类对象的大小 面向过程编程也叫结构化编程.虽然结构化编程的理念提高了程序的清晰度,可靠性,并且方便维护.但它再编写大型的程序时,仍然面临这巨大的挑战,OOP(面向对象编程)提供了一种新的方法.与强调算法的

  • Java全面细致讲解类与对象

    目录 类和对象的关系 类和对象的实例化 static关键字 private实现的封装 构造方法 this关键字 代码块 匿名对象 小结 类和对象的关系 类就是一类对象的统称.对象就是这一类具体化的一个实例. (对象是类的实例化) 对象是什么? 此对象非彼对象!!!说到对象就要提到过程. 面向过程:C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题.面向过程注重的是过程,在整个过程中所涉及的行为,就是功能. 面向对象:JAVA是基于面向对象的,关注的是对象,将一件事情

  • C++简单又轻松的讲解类和对象中友元函数

    目录 友元 浅解概念 友元目的 友元的三种实现 全局函数做友元 类做友元 成员函数做友元 注意事项 总结 友元 用到关键字 friend 浅解概念 举一个非常实际的例子,假如端午节到了你煮了两种粽子,一种是普通的糯米粽子,一种是特殊的五花肉粽子,糯米粽只要是客人都可以品尝,而五花肉棕只限好朋友品尝,这时候就可以用到友元的知识了.在程序里,有些私有属性也想让类外特殊的一些函数或者类访问,就要用到友元函数. 友元目的 让一个函数或者类,访问另一个类的私有属性 友元的三种实现 全局函数.成员函数.类都

  • yui3的AOP(面向切面编程)和OOP(面向对象编程)

    首先请把手放胸前成沉思状:我上了生活,还是被生活上了自己? 没想出答案把,恩,可以读下文了.从语义角度讲,同一事物的不同表述可以反映人的主观视角的不同,从哲学角度将,世界观影响方法论,我们看事物的角度不同,有时会得出截然相悖的结论,从而会影响我们的做事方式和行为准则,现实生活如此,在丰富多彩的编程语言中更是如此,编程模式充满了对现实世界的各种模拟,包括是面向过程,面向对象,还有面向切面.我们大概已经非常熟悉面向过程和面向对象,切面的英文是Aspects(有时译作方面,我感觉用切面更能贴切的表达A

  • Java面向对象类和对象实例详解

    目录 1 - Java面向对象学习的三条主线 2 - 面向过程与面向对象 3 - 面向对象的三大特征 4 - 面向对象分析方法分析问题的思路和步骤 5 - 面向对象的思想概述 6 - 类和对象的创建-内存解析 7 - 类中属性的声明和使用(局部变量与成员变量的区别) 8 - 类中方法的声明和使用 9 - 对象数组的使用 10 - 理解 "万物皆对象" 11 - 匿名对象 12 - 方法的封装(数组常用算法的封装) 总结 1 - Java面向对象学习的三条主线 ①Java类即类的成员:属

  • 全方位讲解Java的面向对象编程思想

    什么是面向对象? Object 对象,Oriendted 以-为导向的, Programming 程序设计 面向对象就是使用对象进行程序设计,简写成OOP. SP和OOP对比 面向对象的三大原则      封装  继承   多态 对象 对象是面向对象编程的核心部分,是实际存在的具体实体,具有明确定义的状态和行为: 对象其实就是"数据"和"函数"的封装体,其中: 数据表示自身的状态,也称作"属性"或"成员数据": 函数表示自身的

  • 浅谈Java实现面向对象编程java oop

    一.对象的综述 面向对象编程(OOP)具有多方面的吸引力.对管理人员,它实现了更快和更廉价的开发与维护过程.对分析与设计人员,建模处理变得更加简单,能生成清晰.易于维护的设计方案.对程序员,对象模型显得如此高雅和浅显.此外,面向对象工具以及库的巨大威力使编程成为一项更使人愉悦的任务.每个人都可从中获益,至少表面如此. 所有编程语言的最终目的都是解决企业又或者人在现实生活中所遇到的问题,最初我们的程序可能长这样"11111100001",相信大家都不会陌生,只是大家没这么子去敲过代码.再

  • js面向对象编程OOP及函数式编程FP区别

    目录 写在前面 javscript 中函数和对象的关系 面向对象编程(OOP) 继承 多态 封装 函数编程编程(FP) 闭包和高阶函数 柯里化 偏函数 组合和管道 函子 写在最后 写在前面 浏览下文我觉得还是要有些基础的!下文涉及的知识点太多,基本上每一个拿出来都能写几篇文章,我在写文章的过程中只是做了简单的实现,我只是提供了一个思路,更多的细节还是需要自己去钻研的,文章内容也不少,辛苦,如果有其他的看法或者意见,欢迎指点,最后纸上得来终觉浅,绝知此事要躬行 javscript 中函数和对象的关

  • Java 类与对象超基础讲解

    目录 什么是面向对象 面向过程与面向对象 类与对象的使用 类与对象的使用与说明 对象的初始化 this的使用 构造方法 this可以调用本类的构造方法 什么是面向对象 Java语言是一个纯面向对象的语言,面向对象的语言不仅只有Java,包括C++,PHP等 面向对象的编程思想简称 OOP(Object Oriented Programming),其基本特点就是封装,继承和多态. 面向过程与面向对象 想要弄清楚什么是面向对象,首先需要知道两者的区别 面向过程更注重程序的每一个步骤,用相应的函数来实

  • 通过Class类获取对象(实例讲解)

    通过Class对象获取对象的方式是通过class.newInstance()方式获取,通过调用默认构造参数实例化一个对象. /** * Created by hunt on 2017/6/27. * 测试的实体类 * @Data 编译后会自动生成set.get.无惨构造.equals.canEqual.hashCode.toString方法 */ @Data public class Person { private String name; private int age; } /** * C

随机推荐