• 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,我们称之为对象。其实想叫作变量也可以,但还是跟着叫对象吧。

            接下来,通过一段代码初步认识类:

     1 # ifndef STOCK00_H
     2 #define STOCK00_H
     3 # include "string"
     4 class Stock
     5 {
     6 private:
     7     std::string company;
     8     long shares;
     9     double share_val;
    10     double total_val;
    11     void set_tot()//思考这个函数定义的意义何在
    12     {
    13         total_val = shares*share_val;
    14     }
    15 public:
    16     Stock::Stock();
    17     void acquire(const std::string &co, long n, double pr);
    18     void buy(long num, double price);
    19     void sell(long num, double price);
    20     void updata(double price);
    21     void show();
    22 };
    23 #endif   //ifbdef...endif成对出现

    这段代码定义了一个名叫Stock的类。首先,我们在这个代码中看到的是:public和private,中文意思公共和私有(这种描述和其功能很吻合)。共有的意思是对外公开的,客户可以对其访问的。我们也把这个叫做接口。私有的意思是用户对其不可直接访问的。上面代码可以看到:我们在private中定义了很多基本类型变量。我们把这些基本类型变量叫做数据成员。而public中定义的是函数成员,我们也叫做方法。当然不一定非要把数据成员都放在private中,而把函数成员都放在public中,取决于你想让用户访问什么。关于这方面,请具体参考c++ prime,并通过自己的实战体会。

    在此,仅仅总结这么个东西(很重要):我们定义了一个类,比如猫科动物。我们首先想到的肯定是:既然是猫科动物,首先肯定要有一些描述它的信息:比如体重啊,毛色啊,名字啊(假如有),甚至眼睛大小啊等等。而这些其实本质上,就是我们说的数据成员,即我们需要定义一些基本类型变量来描述我们的类具有哪些特征。但是现在,我们是面向对象编程:我们需要封装。假如现在有一个用户手上有一只具有这些特征的值的猫,他想根据这些数据知道这个猫几岁了???。这便引入了这样一个问题:我们类的存在不只是为了存储一只猫的各类类型的值。(那样的话我们直接用结构体就好了,为何要使用类呢???),我们是想根据这些值能 做些什么比较方便的事,而这些事最终被反馈到用户。那么成员函数的存在就是:利用这些基本类型变量,完成某项工作。但用户并不需要知道怎么完成,我只需要知道猫有几岁???知道猫有几岁这个工作毫无疑问是通过函数完成的,或者说我们用什么方法(函数)来知道猫有几岁(过度很自然)。比如有一个函数indicate_age()可以帮我们做这件事,则用户可以通过调用类——猫中的indicate_age()方法来实现这个愿望。这一点也表明了,这个indicate_age()方法要放在public,这样用户才有访问使用它的权限。(假如用户不想让人知道名字,可以放在private中)

    (如果清闲,可以思考Python中定义类有何异同)

    请注意,上面那段代码中public中只是声明了函数原型,但是并没定义这些函数,当然我们可以在public中直接定义,但没必要,显得很啰嗦。下面给出这些函数的定义:

     1 # include "iostream"
     2 # include "stock00.h"
     3 
     4 void Stock::acquire(const std::string &co, long n, double pr)
     5 {
     6     company = co;
     7     if (n < 0)
     8     {
     9         std::cout << "Number of shares can't be negative;"
    10             << company << "shares set to 0.
    ";
    11         shares = 0;
    12     }
    13     else
    14         shares = n;
    15     share_val = pr;
    16     set_tot();
    17 }
    18 
    19 void Stock::buy(long num, double price)
    20 {
    21     if (num < 0)
    22     {
    23         std::cout << "Number of shares can't be negative."
    24             << "Transaction is aborted.
    ";
    25     }
    26     else
    27     {
    28         shares += num;
    29         share_val = price;
    30         set_tot();
    31     }
    32 }
    33 
    34 void Stock::sell(long num, double price)
    35 {
    36     using std::cout;
    37     if (num < 0)
    38     {
    39         cout << "Number of shares can't be negative."
    40             << "Transaction is aborted.
    ";
    41     }
    42     else if (num>shares)
    43     {
    44         cout << "You can't sell more than you have!"
    45             << "Transaction is aborted.
    ";
    46     }
    47     else
    48     {
    49         shares -= num;
    50         share_val = price;
    51         set_tot();
    52     }
    53 }
    54 
    55 void Stock::updata(double price)
    56 {
    57     share_val = price;
    58     set_tot();
    59 }
    60 
    61 void Stock::show()
    62 {
    63     std::cout << "Company:" << company
    64         << "Shares:" << shares << "
    "
    65         << "Shares Price:$" << share_val
    66         << "Total worth:$" << total_val << std::endl;
    67 }
    68 
    69 Stock::Stock()
    70 {
    71     company = "no name";
    72     shares = 0;
    73     share_val = 0.0;
    74 }

    我们重新用一个文件来定义这些函数:具体的细节不再赘述,想描述的是每个函数的抬头,都采用了Stock::,这其实是表明这些函数的作用域是类作用域,比如我们外面也声明了acquire()函数,那么两者是可以区分的。这个类作用域十分重要,具体的可以参考c++ prime,

    在这里,我们发现,给出的第一个代码中,有这样一个函数:Stock::Stock(),这个函数对类的数据成员进行了赋值(实际上就是初始化)。这个函数有两个特点:1 没有返回类型;2 名字和类的名字要一致。我们把这种函数叫构造函数。实际编写代码中,我们有时候没有写构造函数,但是貌似并不是报错,但这并不意味着构造函数是非必须的。实际上,构造函数是必须的。我们在创建类 对象的时候(就是定义类 变量的时候)将先自动调用构造函数(即由系统自动调用),然后才能生成我们的类 对象。也就是构造函数是用来被创建对象的,从而构造函数是不能通过对象去调用的。这一是十分重要的。关于构造函数耳朵显示,和隐式初始化可以参考c++ primer。

    上面完成了对一个类的定义。下面给出调用它的代码:

     1 #  include"iostream"
     2 #  include"stock00.h"
     3 int main()
     4 {
     5     Stock fluffy_the_car;
     6     fluffy_the_car.acquire("NanoSmart", 20, 12.50);
     7     fluffy_the_car.show();
     8     fluffy_the_car.buy(15, 18.125);
     9     fluffy_the_car.show();
    10     fluffy_the_car.sell(400, 20.00);
    11     fluffy_the_car.show();
    12     fluffy_the_car.buy(300000, 40.125);
    13     fluffy_the_car.show();
    14     system("pause");
    15     //int i;
    16     //std::cout << "i is:" << i << std::endl;//c++中未初始化造成报错,不同于C语言.
    17     return 0;
    18 }

    上面的代码是多么的简洁,假如我们是客户,我们只需要知道类方法怎么使用即可,即怎么调用接口,就能知道我们的猫有几岁。站在用户的角度讲,这段程序很简单!!!而这,就是类产生的目的!!!

            C++中类的诞生是一种很重要的思想,而所有关于C++类相关的,最重要的思想在于:能够让我们像使用其他类一样方便的使用我们定义的自己数据类型。认识到这一点的重要性在于:当我们思想中认识到我们自己创建的类和int,char并无区别的时候,就意味着,int,char ,double这些基本类型所有的操作,定义的类对象也应该有:比如,初始化,赋值,甚至比较大小。具有指针,具有数据(类数组),可以将类作为函数的返回值和参数。所以,我们思考类的角度,应该从数据和结构的角度去思考!

    关于类:还想说明两点很重要的地方:

    1  声明类只是创建了对象的形式,而非创建对象本身。因此,在创建对象之前,我们所定义的东西,是不被分配内存空间的,比如当我们声明int类型的时候,只有定义了 int i,i才有内存空间

    2  关于类的作用域。在很多地方,都讨论过作用域。作用域到底意味着什么???作用域意味着变量的生存周期,意味着作用域与作用域之间的独立性。而类的作用域,一个最明显的特征是,当我们定义类方法的时候,采用的是:classname ::funcname  这样的限定方式,这样即使两种方法使用了同一个名字,但由于处于不同的类作用域中,两者的同时存在并不冲突!

  • 相关阅读:
    Java基础学习总结(42)——Log4j 2使用教程
    Java基础学习总结(42)——Log4j 2使用教程
    Myeclipse学习总结(1)——Myeclipse优化配置
    Python不再为字符集编码发愁,使用chardet轻松解决你的困扰。
    补习系列(6)- springboot 整合 shiro 一指禅
    给一线讲产品·8期|VPC、子网、安全组,是什么关系?
    Python不再为字符集编码发愁,使用chardet轻松解决你的困扰。
    python推导式pythonic必备
    【nodejs原理&源码赏析(6)】深度剖析cluster模块源码与node.js多进程(下)
    【nodejs原理&源码赏析(5)】net模块与通讯的实现
  • 原文地址:https://www.cnblogs.com/shaonianpi/p/9853246.html
Copyright © 2020-2023  润新知