精选文章 C++入门篇02

C++入门篇02

作者:weixin_34037173 时间: 2021-02-07 02:17:00
weixin_34037173 2021-02-07 02:17:00
【摘要】点击链接加入群【C语言】:http://jq.qq.com/?_wv=1027&k=2H9sgjG    上一小节主要讨论了引用,其实大家对指针的理解到位了,这些东西都很简单啦。这小节,我们就来进入C++中的重要概念啦,类。还记得C中的结构体吗,可以用来描述事物,但是只能描述它们的属性,如Person结构,有名字,有年龄,但是它不能拥有方法,什么意思呢?比如人会吃饭,人会看书,人会浏览技术博...

点击链接加入群【C语言】:http://jq.qq.com/?_wv=1027&k=2H9sgjG



上一小节主要讨论了引用,其实大家对指针的理解到位了,这些东西都很简单啦。

这小节,我们就来进入C++中的重要概念啦,类。还记得C中的结构体吗,可以用来描述事物,但是只能描述它们的属性,如Person结构,有名字,有年龄,但是它不能拥有方法,什么意思呢?比如人会吃饭,人会看书,人会浏览技术博客,但是结构定义的这个 Person 是不行的,但是我们也可以实现一种方式:

void Read(const Person * p,const char * bookname)

{

printf("%s is reading %s\n",p->name,bookname); //用指针访问成员用 -> 用对象访问成员用.

}

这样也可以实现某种功能,但是在C++中,我们对这种结构进行扩展,让它本身可以拥有方法(就是我们说的函数),这个就是C++里的类啦。


#include

class Persn

{

public:

intm_age;

char  *m_name;

public:

voidRead(const char * bookname)

{

printf("%s is reading %s\n",m_name,bookname);

}

};

int main()

{

Persn p;

p.m_age = 28;

p.m_name = "周星驰";

p.Read("大话西游");

return 0;

}


代码很简单,其实大家可以理解的,我们讲过代码只不过是 一些二进制代码的组合,放在哪里都是可以的,只要编译和链接过程中能够保证在调用的时候能找到它们就可以了。

所以我们现在的Person类有Read这个方法 ,很好理解吧,大家不用研究很深滴。这是一种思想的转变,从上面的Eat到现在的Eat的转变,大家能有所感触吧,或者你能体会到它们是不一样的过程就OK啦。下面是一种面向对象的思想,我们以后的工作都是在设计并实现一些类,这些类有很强大的功能。


现在大家要理解的一个东西是,代码就是二进制代码,写进.EXE中去啦,不管是以类的方式还是以什么的方式都可以。


下面我们来深入一下对类的了解。

其实就像我们定义一个 int val =12; 这样,也是有一个过程滴,就是在栈中申请内存,其实上面的Person p;也是在栈中申请内存啦,大家自己调试一下就会明白啦。

而我们写p.m_age 仅仅是为 p 对象的 前四个字节赋值,p.m_name 是对p对象的后四个字节赋值,那么我们调用p.Read就是调用为这个类生成的代码啦,可以想像一下,每一个类都可以有多种函数,可以再试想一下,这些代码肯定会有一个界限,就是A类的在A里面,B类的在B里面,这就是范围啦,对吧,其实这种思想很普遍,比如我们在main函数中定义的变量是在栈中存储的,在所有函数之外定义的变量是在数据区存储的,也叫全局变量,这就是一种范围上的划分吧,总之大家要理解好,我们在C++中称这种划分为作用域,你只要理解了思想,其实的什么都好说,既然有了作用范围,那么自然而然的我们也就会想到对象应该有生命周期,举个例子,在main函数中定义的变量,到main函数返回的时候就没有意义啦,也就是它的生命周期结束啦。


类跟普通的类型的区别就是它可以拥有方法,而且每个类还有两个特殊的方法,一个叫构造函数,一个叫析构函数。

构造函数的用处就是用来初始化类中的成员滴,如m_name,m_age, 析构函数就是用来销毁一些数据滴,这是编译器决定滴,也就当我们创造一个对象的时候,系统会自动调用它的构造函数,再对象的生命周期结束的时候,系统会自动调用它的析构函数。

很多书上会讲如果一个类没有定义构造函数,那么编译系统会为它添加一个默认的构造函数,虽然这不是什么重点,但是我们可以通过汇编代码看一下上面的例子,

00401036  rep stos  dword ptr [edi]

16: Persn p; //这里并没有调用默认构造函数

17: p.m_age = 28;

00401038  mov dword ptr [ebp-8],1Ch

18: p.m_name = "周星驰";

0040103F  mov dword ptr [ebp-4],offset string "\xd6\xdc\xd0\xc7\xb3\xdb" (00422028)

19: p.Read("大话西游");

00401046  push offset string "\xb4\xf3\xbb\xb0\xce\xf7\xd3\xce" (0042201c)

0040104B  lea ecx,[ebp-8]

0040104E  call @ILT+0(Persn::Read) (00401005)


好了,那么我们来为它加上一个构造函数吧。

#include

#include

#include

class Persn

{

public:

intm_age;

char  *m_name;

public:

Persn()

{

printf("构造函数被调用\n");

m_name = NULL;

m_name = (char *)malloc(20);

}

~Persn()

{

printf("析构函数被调用\n");

if (m_name != NULL)

{

free(m_name);

}

m_name = NULL;

}

voidRead(const char * bookname)

{

printf("%s is reading %s\n",m_name,bookname);

}

};

int main()

{

Persn p;

p.m_age = 28;

strcpy(p.m_name,"周星驰");

p.Read("大话西游");

return 0;

}

这个程序一运行,会看到先调用了构造函数,又调用了析构函数。如果你还不理解构造与析构,那么我再来总结一下,就是系统在构造这个对象之前,给我们一次机会,让我们对成员变量(如 m_age)做初始化,而析构函数也是在对象生命周期要结束的时候给我们一次机会,就是让我们做一些收尾工作(比如上面的free)。


在上面的代码中,我们有一个内容没有介绍,就是 #include,这里面写的是 cstdlib, cstdio  cstring,为什么这样写,在C++中,我们建议写这些,而不是stdio.h等,

也就是在C++中,我们要使用C语言中的一些库函数,头文件写成 (c stdio .h  ),将.H去掉,在前面加个字母c,很好理解吧。


现在大家应该知道,类有两个特殊函数,构造和析构,还知道了作用域和生命周期的概念。


那么我们还在代码中加上了 public 关键字,大家先就这样子用吧,以后再分析。


现在的问题是如果我们的类很大,写在同一个文件中很不好看,那么我们就要把它抽取出来。


Person.h

#include

#include

#include

class Persn

{

public:

intm_age;

char  *m_name;

public:

Persn();

~Persn();

voidRead(const char * bookname);

};



Person.cpp

#include "Person.h"

Persn::Persn()

{

printf("构造函数被调用\n");

m_name = NULL;

m_name = (char *)malloc(20);

}

Persn::~Persn()

{

printf("析构函数被调用\n");

if (m_name != NULL)

{

free(m_name);

}

m_name = NULL;

}

voidPersn::Read(const char * bookname)

{

printf("%s is reading %s\n",m_name,bookname);

}


Test.cpp

#include "Person.h"

int main()

{

Persn p;

p.m_age = 28;

strcpy(p.m_name,"周星驰");

p.Read("大话西游");

return 0;

}



大家只要把这三个文件创建出来,将代码打出来就行了,然后再从全局的角度来看这段代码


我们在Person.cpp里写Person类的函数实现的时候,加上了 Person::  大家能猜到这是什么吗?作用域标识符,哈哈,就是说这个函数是 Person类特有的,那么比如,我们要调用一些全局函数怎么办,就用全局作用域标识符,怎么写 ::,就这么简单,举个例子比较好理解哦。

#include

class CFindWindow

{

public:

HWNDm_Window;

CFindWindow():m_Window(NULL)

{

//这里我们使用的是参数列表的形式进行初始化,多个参数之间用逗号隔开

}

voidFindWindow(const char * className = NULL,const char * windowName = NULL)

{

HWND temHwnd = ::FindWindow(className,windowName);

if (temHwnd != NULL)

{

m_Window = temHwnd;

}

}

};

int main()

{

CFindWindowobj;

obj.FindWindow("Notepad");

return 0;

}

这段代码中我们写了一个用来查找系统中是不是存在某个窗口,我们在运行这段代码的时候应该先按 WIN 键 + R ,WIN键不知道是哪个?就是键盘上的窗口键,按下这个组合键后会弹出运行对话框,在里面输入notepad 后回车,会打开一个记事本窗口,然后我们在obj.FindWindow那句下断点,调试程序,会发现没调用函数之前,obj.m_Window的值是0,调用后,它就有值了,我们在这里封装的这个在里面提供了一个FindWindow的方法,WINDOWS系统提供的用来查找窗口的API函数也是这个名字,怎么办呢,我们要调用API,所以就加上 :: 全局作用域标识符,来告诉系统,我们调用的是系统提供的全局函数,而不是我们这个类的这个FindWindow,不然的话,就成什么呀,递归嘛。。不过好像没有出口吧,而且我们讲过没出口的递归是不应该出现滴,以后再看MFC中的很多函数,都是对API的一种封装,就像我们现在这样类似。


还介绍了一个初始化列表,就是在 构造函数的()后面 加上 :成员变量1(初始值),成员变量2(初始值),成员变量3(初始值){ } , 当然这个操作也可以只对部分成员做初始化。

好啦,我们已经讲的很多啦。

再一介绍一下 public的意思,这个意思嘛,就是说明,我们在main函数中可以访问的意思,如 obj.FindWindow ,这个操作是在main函数中进行滴,如果改成 private或protect 会导致编译出错,那么它们又是什么意思呢。

private 说明这个成员是这个类私有的,只允许这个类的成员函数进行访问,如

class A

{

private:

int m_data;

public:

void fun(){ //在这里面可以访问m_data}  //但是在main函数中定义A obj. obj.m_data是不行滴。理解了吧,所以说数据一般私有化,我们一般提供一个公有函数来对它进行访问

}

protect:表示这个成员可以被派生类访问,以后再介绍。


其实我们在真正的项目中,对应用程序的数据控制一般不会很严格,一般就是 数据私有化,方法公有化。


下一小节,要给大家介绍一下C++ 的简单模板技术。 很给力吧。


转载于:https://blog.51cto.com/qianqianquege/1312925

勿删,copyright占位
您找到想要的结果了吗?
C++入门篇02
提交成功!非常感谢您的反馈,我们会继续努力做到更好
分享文章到微博
分享文章到朋友圈

上一篇:利用CSS、JavaScript及Ajax实现图片预加载的三大方法

下一篇:凯撒(Caesar)密码加密解密c语言

您可能感兴趣

  • C++运算符

    C++提供了以下运算符: 算术运算符 +(加)-(减) *(乘) /(除)  %(整除求余)++(自加) --(自减)关系运算符 >(大于)<(小于)  ==(等于)>=(大于或等于)<=(小于或等于)!=(不等于)逻辑运算符 &&(逻辑与) ||(逻辑或)  !(逻辑非)位运算符 <<(按位左移)  >>(按位右移)  &(按位与...

  • C++多线程及CUDA编程(一)

    一、前言        这是我的第一篇博客,目的是记录在研究生阶段进行的多线程并行计算,主要用到的是VS2013与CUDA8.0,前者安装比较方便,后者配置起来有些麻烦,会遇到一些小问题导致无法进行Debug。希望我所分享的经验能够让我牢记其用法以及给对这方面有兴趣的人一些启发。 二、CUDA8.0的安装及配置 (1)首先请去点击打开链接下载CUDA...

  • C# C++ 字符串传递

    可以说新手使用P-INVOKE最开始的头疼就是C#和C++的字符串传递,因为这里涉及到两个问题。 第一:C#的string和C++的字符串首指针如何对应。 第二:字符串还有ANSI和UNICODE(宽字符串)之分。   本文分三部分阐述: 第一:字符串指针当输入参数, 第二:字符串指针作为返回值, 第三:字符串指针作为输入输出参数。 ...

  • C++中类成员函数做友元函数为什么报错?

    最近在使用友元函数来访问私有成员时,遇到了问题,用一个类成员函数做另一个类的友元函数,但是一直报错,提示为定义其中的一个类型,思考良久(思路:既然友元函数在公有访问权限内,就应该可以访问私有数据成员),在网上搜了很多的博客,但是都没有明确的答案,还好最后自己解决了问题,下面写一下自己解决问题的过程,根据个人的理解写了一下注释(也不知道理解的对不对),...

  • 从小白开始学C++ 说明符、限定符、new的两种用法

    说明符和限定符 auto : 将变量声明位自动变量register : 将变量声明为寄存器存储类型static : 被用于局部声明中,表示局部变量的存储持续性为静态extern : 表明是引用声明,即声明引用在其他地...

  • c++搞定大端小端

    存储模式 小端存储:数据的低字节存储在地址空间的低字节位,数据的高字节存储在地址空间的高字节位。 大端存储:数据的低字节存储在地址空间的高字节位,数据的高字节存储在地址空间的低字节位。 判断计算机是小端还是大端的...

  • C++ 运算符重载讲解与经典实例

    C++中预定义的运算符的操作对象只能是基本数据类型,实际上,对于很多用户自定义类型,也需要有类似的运算操作。例如:  class complex {  public:   complex(double r=0.0,double I=0.0){real=r;imag=I;}   void display();  private:   double r...

  • JS后端框架 Nest.js入门篇 中间件aop、Middleware(四)

    注:此文仅记录博主初次学习nestjs之后的认识和理解,经验尚浅,文章内容仅供参考,如若有误,敬请指正。 作为切面 此文暂不对细节展开探讨 1.切面类型:NestMiddleware接口实现类 2.切面输入 ...

CSDN

CSDN

中国开发者社区CSDN (Chinese Software Developer Network) 创立于1999年,致力为中国开发者提供知识传播、在线学习、职业发展等全生命周期服务。
C++入门篇02介绍:华为云为您免费提供C++入门篇02在博客、论坛、帮助中心等栏目的相关文章,同时还可以通过 站内搜索 查询更多C++入门篇02的相关内容。| 移动地址: C++入门篇02 | 写博客