c++入门之浅入浅出类——分享给很多想形象理解的人
引入类之前,首先引入一个古老的话题:类别,比如int ,char ,double;这些基本的类型方便了我们描述数据(请注意,这句话很重要),类型的存在就是为了方便我们描述数据的。而c++中的类其实作用也是:方便我们描述数据。因此,我们可以这么认为:引入类的作用,就是为了让我们可以像使用int 这些类型一样,来描述我们想要表达的数据。尽管很多时候我们需要把我们想描述的数据抽象化。因此,我们有理由将类和int,char这些基本类型一视同仁(这个思想是很重要的!!!,但要在编程的时候认识到这点并不容易)。而实质上,引入类的初衷:就是让我们能够像使用基本类型使用我们定义的类,并能够像基本类型那样操作自如。
再看一个基本的话题:比如定义了一个变量 ,比如int x;很不幸的是,我们已经养成了习惯,习惯把x叫作“变量”,同样的把int叫作类型,这对我们认识和使用类造成了很大的不便。在类中,也会定义类变量,但我们把它叫对象。比如,我们定义猫科动物为一类:class Cat{};通常类型名大写,请注意,这里的Cat是我们定义的类,或者说是类型。即Cat和int,char等并无差异性。比如我们可以通过这个Cat类型,定义一些猫科动物。比如Cat cat(就是定义了猫),Cat tiger(定义了老虎)。我们发现:猫和老虎都是猫科动物(就像1和2都是整数一样)。这里的cat,tiger,我们称之为对象。其实想叫作变量也可以,但还是跟着叫对象吧。
接下来,通过一段代码初步认识类:
# ifndef STOCK00_H
#define STOCK00_H
# include "string"
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot()//思考这个函数定义的意义何在
{
total_val = shares*share_val;
}
public:
Stock::Stock();
void acquire(const std::string &co, long n, double pr);
void buy(long num, double price);
void sell(long num, double price);
void updata(double price);
void show();
};
#endif //ifbdef...endif成对出现
这段代码定义了一个名叫Stock的类。首先,我们在这个代码中看到的是:public和private,中文意思公共和私有(这种描述和其功能很吻合)。共有的意思是对外公开的,客户可以对其访问的。我们也把这个叫做接口。私有的意思是用户对其不可直接访问的。上面代码可以看到:我们在private中定义了很多基本类型变量。我们把这些基本类型变量叫做数据成员。而public中定义的是函数成员,我们也叫做方法。当然不一定非要把数据成员都放在private中,而把函数成员都放在public中,取决于你想让用户访问什么。关于这方面,请具体参考c++ prime,并通过自己的实战体会。
在此,仅仅总结这么个东西(很重要):我们定义了一个类,比如猫科动物。我们首先想到的肯定是:既然是猫科动物,首先肯定要有一些描述它的信息:比如体重啊,毛色啊,名字啊(假如有),甚至眼睛大小啊等等。而这些其实本质上,就是我们说的数据成员,即我们需要定义一些基本类型变量来描述我们的类具有哪些特征。但是现在,我们是面向对象编程:我们需要封装。假如现在有一个用户手上有一只具有这些特征的值的猫,他想根据这些数据知道这个猫几岁了???。这便引入了这样一个问题:我们类的存在不只是为了存储一只猫的各类类型的值。(那样的话我们直接用结构体就好了,为何要使用类呢???),我们是想根据这些值能 做些什么比较方便的事,而这些事最终被反馈到用户。那么成员函数的存在就是:利用这些基本类型变量,完成某项工作。但用户并不需要知道怎么完成,我只需要知道猫有几岁???知道猫有几岁这个工作毫无疑问是通过函数完成的,或者说我们用什么方法(函数)来知道猫有几岁(过度很自然)。比如有一个函数indicate_age()可以帮我们做这件事,则用户可以通过调用类——猫中的indicate_age()方法来实现这个愿望。这一点也表明了,这个indicate_age()方法要放在public,这样用户才有访问使用它的权限。(假如用户不想让人知道名字,可以放在private中)
(如果清闲,可以思考Python中定义类有何异同)
请注意,上面那段代码中public中只是声明了函数原型,但是并没定义这些函数,当然我们可以在public中直接定义,但没必要,显得很啰嗦。下面给出这些函数的定义:
# include "iostream"
# include "stock00.h" void Stock::acquire(const std::string &co, long n, double pr)
{
company = co;
if (n < )
{
std::cout << "Number of shares can't be negative;"
<< company << "shares set to 0.\n";
shares = ;
}
else
shares = n;
share_val = pr;
set_tot();
} void Stock::buy(long num, double price)
{
if (num < )
{
std::cout << "Number of shares can't be negative."
<< "Transaction is aborted.\n";
}
else
{
shares += num;
share_val = price;
set_tot();
}
} void Stock::sell(long num, double price)
{
using std::cout;
if (num < )
{
cout << "Number of shares can't be negative."
<< "Transaction is aborted.\n";
}
else if (num>shares)
{
cout << "You can't sell more than you have!"
<< "Transaction is aborted.\n";
}
else
{
shares -= num;
share_val = price;
set_tot();
}
} void Stock::updata(double price)
{
share_val = price;
set_tot();
} void Stock::show()
{
std::cout << "Company:" << company
<< "Shares:" << shares << "\n"
<< "Shares Price:$" << share_val
<< "Total worth:$" << total_val << std::endl;
} Stock::Stock()
{
company = "no name";
shares = ;
share_val = 0.0;
}
我们重新用一个文件来定义这些函数:具体的细节不再赘述,想描述的是每个函数的抬头,都采用了Stock::,这其实是表明这些函数的作用域是类作用域,比如我们外面也声明了acquire()函数,那么两者是可以区分的。这个类作用域十分重要,具体的可以参考c++ prime,
在这里,我们发现,给出的第一个代码中,有这样一个函数:Stock::Stock(),这个函数对类的数据成员进行了赋值(实际上就是初始化)。这个函数有两个特点:1 没有返回类型;2 名字和类的名字要一致。我们把这种函数叫构造函数。实际编写代码中,我们有时候没有写构造函数,但是貌似并不是报错,但这并不意味着构造函数是非必须的。实际上,构造函数是必须的。我们在创建类 对象的时候(就是定义类 变量的时候)将先自动调用构造函数(即由系统自动调用),然后才能生成我们的类 对象。也就是构造函数是用来被创建对象的,从而构造函数是不能通过对象去调用的。这一是十分重要的。关于构造函数耳朵显示,和隐式初始化可以参考c++ primer。
上面完成了对一个类的定义。下面给出调用它的代码:
# include"iostream"
# include"stock00.h"
int main()
{
Stock fluffy_the_car;
fluffy_the_car.acquire("NanoSmart", , 12.50);
fluffy_the_car.show();
fluffy_the_car.buy(, 18.125);
fluffy_the_car.show();
fluffy_the_car.sell(, 20.00);
fluffy_the_car.show();
fluffy_the_car.buy(, 40.125);
fluffy_the_car.show();
system("pause");
//int i;
//std::cout << "i is:" << i << std::endl;//c++中未初始化造成报错,不同于C语言.
return ;
}
上面的代码是多么的简洁,假如我们是客户,我们只需要知道类方法怎么使用即可,即怎么调用接口,就能知道我们的猫有几岁。站在用户的角度讲,这段程序很简单!!!而这,就是类产生的目的!!!
C++中类的诞生是一种很重要的思想,而所有关于C++类相关的,最重要的思想在于:能够让我们像使用其他类一样方便的使用我们定义的自己数据类型。认识到这一点的重要性在于:当我们思想中认识到我们自己创建的类和int,char并无区别的时候,就意味着,int,char ,double这些基本类型所有的操作,定义的类对象也应该有:比如,初始化,赋值,甚至比较大小。具有指针,具有数据(类数组),可以将类作为函数的返回值和参数。所以,我们思考类的角度,应该从数据和结构的角度去思考!
关于类:还想说明两点很重要的地方:
1 声明类只是创建了对象的形式,而非创建对象本身。因此,在创建对象之前,我们所定义的东西,是不被分配内存空间的,比如当我们声明int类型的时候,只有定义了 int i,i才有内存空间
2 关于类的作用域。在很多地方,都讨论过作用域。作用域到底意味着什么???作用域意味着变量的生存周期,意味着作用域与作用域之间的独立性。而类的作用域,一个最明显的特征是,当我们定义类方法的时候,采用的是:classname ::funcname 这样的限定方式,这样即使两种方法使用了同一个名字,但由于处于不同的类作用域中,两者的同时存在并不冲突!
c++入门之浅入浅出类——分享给很多想形象理解的人的更多相关文章
- 浅入深出Vue:代码整洁之封装
深入浅出vue系列文章已经更新过半了,在入门篇中我们实践了一个小小的项目. <代码整洁之道>一书中提到过一句话: 神在细节中 这句话来自20世纪中期注明现代建筑大师 路德维希·密斯·范·德 ...
- Spring浅入浅出——不吹牛逼不装逼
Spring浅入浅出——不吹牛逼不装逼 前言: 今天决定要开始总结框架了,虽然以前总结过两篇,但是思维是变化的,而且也没有什么规定说总结过的东西就不能再总结了,是吧.这次总结我命名为浅入浅出,主要在于 ...
- Spring的数据库编程浅入浅出——不吹牛逼不装逼
Spring的数据库编程浅入浅出——不吹牛逼不装逼 前言 上文书我写了Spring的核心部分控制反转和依赖注入,后来又衔接了注解,在这后面本来是应该写Spring AOP的,但我觉得对于初学者来说,这 ...
- 浅入浅出EmguCv(一)OpenCv与EmguCv
最近接触计算机视觉方面的东西,于是准备下手学习opencv,从官网下载windows的安装版,配置环境,一系列步骤走完后,准备按照惯例弄个HelloWord.也就是按照网上的教程,打开了那个图像处理领 ...
- 浅入深出之Java集合框架(上)
Java中的集合框架(上) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架 ...
- 浅入深出之Java集合框架(中)
Java中的集合框架(中) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架 ...
- 浅入深出之Java集合框架(下)
Java中的集合框架(下) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,哈哈这篇其实也还是基础,惊不惊喜意不意外 ̄▽ ̄ 写文真的好累,懒得写了.. ...
- 浅入深出Vue:前言
浅入深出Vue系列文章 之前大部分是在做后端,后来出于某些原因开始接触Vue.深感前端变化之大,各种工具.框架令人眼花缭乱.不过正是这些变化,让前端开发更灵活. 博主在刚开始时,参考官网的各个步骤以及 ...
- 包学会之浅入浅出Vue.js:结业篇(转)
蔡述雄,现腾讯用户体验设计部QQ空间高级UI工程师.智图图片优化系统首席工程师,曾参与<众妙之门>书籍的翻译工作.目前专注前端图片优化与新技术的探研. 在第一篇<包学会之浅入浅出Vu ...
随机推荐
- Foreach用法
循环语句是编程的基本语句,在C#中除了沿用C语言的循环语句外,还提供了foreach语句来实现循环.那么我要说的就是,在循环操作中尽量使用foreach语句来实现. 为了来更好地说明为什么要提倡使 ...
- linux源
系统:centos7 x86_64 一.配置本地yum源 1.1加载光驱 1.2挂载到系统 注:如果要长期使用最好把整个镜像文件拷贝到系统下 1.3配置文件 路径/etc/yum.repos.d/ 打 ...
- redis常用命令及结构
##常用结构及命令: keys * #查询所有key randomkey #随机返回key type key #返回key的类型 exists key #判断key是否存在 del key1 key2 ...
- centos7 Docker私有仓库搭建及删除镜像
如果不想用私有镜像库,你可以用docker的库 https://hub.docker.com 环境准备 环境:两个装有Docker 17.09.0-ce 的centos7虚拟机 虚拟机一:192.16 ...
- Java虚拟机(Java Virtual Machine)
JVM(Java Virtual Machine),Java虚机机,是JDK最底层的东西.只要能将源代码编译成字节码(.class)文件,就可以由JVM在不同平台上解释成机器指令来执行.所以,Java ...
- C语言的main函数到底该怎么写
公众号[编程珠玑]:专注但不限于分享计算机编程基础,Linux,C语言,C++,Python,数据库等编程相关[原创]技术文章,号内包含大量经典电子书和视频学习资源.欢迎一起交流学习,一起修炼计算机“ ...
- linux下c程序 daemon、fork与创建pthread的顺序问题
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/shuyun123456789/article/details/34418875 近期发如今写linu ...
- Get https://192.168.2.119/v2/: dial tcp 192.168.2.119:443: getsockopt: connection refused
Get https://192.168.2.119/v2/: dial tcp 192.168.2.119:443: getsockopt: connection refused
- Python selenium ActionChains 基本操作
ActionChains类继承自object类,但是需要为其传入一个driver对象,即ActionChains(driver) 此类常用于模拟鼠标键盘操作,其API列表如下: perform() ...
- Python *args 和 **kwargs用法
*args的参数形式把剩下的没有关键字的参数收起来形成一个tuple,*kwargs把有关键字的收起来做成一个字典 def this_fun(a,b,*args,**kwargs): print a ...