zoukankan      html  css  js  c++  java
  • C++之类与对象(2)

    C++之类与对象(2)

    http://www.cnblogs.com/CaiNiaoZJ/archive/2011/07/24/2115041.html

    接着上一节,今天讲C++中类的构造函数与析构函数,对象的赋值与复制.

      1.用过C#语言的人,都知道构造函数是一种特殊的成员函数,它主要用于对对象分配空间,进行初始化。构造函数的名字必须与类名相同。可以有任何类型的参数,但不返回任何值,是在建立对象时自动执行的。和上一节一样,还是用Kid类来说明。

    class Kid
    {
    private:
    int age;
    char*name;
    char*sex;
    public:
    Kid(int age,char*name,char*sex);
    void showKid();
    };

    Kid::Kid(int age,char*name,char*sex)
    {
    Kid::age=age;
    Kid::name=name;
    Kid::sex=sex;
    }

    void Kid::showKid()
    {
    cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;
    }

    接下来,建立对象并初始化:Kid kid(10,"rookie_j","男");另外一种使用new运算符动态建立对象:Kid *ptr=new Kid(10,"rookie_j","男");通过指针变量ptr来访问:ptr->showKid();当我们用new建立对象时,当不再使用它时,要用delete运算符释放它:delete ptr;和不同成员函数一样,如果构造函数定义在类体内部,则作为内联函数处理;

      在声明类时,对数据成员的初始化一般在构造函数中用赋值语句进行,但C++还提供了另外一种初始化数据成员的方法——用成员初始化表来实现对数据成员的初始化。它的一般形式为:类名::构造函数名([参数表]):[(成员初始化表)];成员初始化表的形式为:成员名1(初始值1),成员名2(初始值2),成员名2(初始值2);比如:

    Kid::Kid(int age,char *name,char *sex):age(age),name(name),sex(sex){};

      接下来讲一下析构函数:在我第一次在C++里看到这个名词时,感觉这个知识点很深奥,结果看了以后,其实很简单。它的作用和构造函数刚好相反,用于撤销对象,如:释放分配给对象的内存空间。析构函数和构造函数名相同,但在其前面要加~符号,析构函数没有参数,也没有返回值,且不能重载,因此一个类中只有一个析构函数。以下三种情况,当对象的生命周期结束时,析构函数会被自动调用:(1)定义了全局对象,则在程序流程离开其作用域(如:main函数结束或调用Exit)时,调用该全局对象的析构函数;(2)对象被定义在函数体里,则当这个函数执行完后,该对象释放,析构函数被自动调用;(3)若一个对象使用new运算符动态创建的,在使用delete运算符释放它时,会自动调用析构函数;

    #include "stdafx.h"
    #include <iostream>

    usingnamespace std;

    class Kid
    {
    private:
    int age;
    char*name;
    char*sex;
    public:
    Kid(int age,char*name,char*sex);
    ~Kid();
    void showKid();
    };


    Kid::Kid(int age,char*name,char*sex)
    {
    Kid::age=age;
    Kid::name=newchar[strlen(name)+1];
    strcpy(Kid::name,name);
    Kid::sex=newchar[strlen(sex)+1];
    strcpy(Kid::sex,sex);
    }

    Kid::~Kid()
    {
    cout<<"dispose object kid"<<endl;
    delete []name;
    delete []sex;
    }

    void Kid::showKid()
    {
    cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;
    }


    int main()
    {
    Kid kid(10,"rookie_j","男");
    kid.showKid();

    Kid *ptr=new Kid(10,"rookie_x","女");
    ptr->showKid();

    delete ptr;

    return0;
    }

    结果:

      如果没有给类定义构造函数,则编译系统自动地生成一个默认的构造函数,比如在Kid类中编译系统会为其产生一个Kid::Kid(){};构造函数,这个默认的构造函数只能给对象开辟存储空间,不能给数据成员赋值,这时数据成员的初值就是随机数。对没有定义构造函数的类,其公有数据成员可以用初始化值表进行初始化,如:

    class Kid
    2 {
    3 public:
    4 int age;
    5 char*name;
    6 char*sex;
    7 };
    8
    9 int main()
    10 {
    11
    12 Kid kid={10,"Rookie_j","男"};
    13 cout<<"姓名:"<<kid.name<<endl<<"年龄:"<<kid.age<<endl<<"性别:"<<kid.sex<<endl;
    14
    15 return0;
    16 }

    但只要一个类定义了构造函数,系统将不再给它提供默认构造函数;另外还有默认的析构函数(Kid::~Kid(){}),一般来说默认的析构函数就能满足要求,但对一些需要做一些内部处理的则应该显式定义析构函数。带默认参数的构造函数和之前所说的带参数的成员函数是一样的,对于构造函数的重载,在这里我就不多说了,只想强调一点,如果是无参的构造函数创建对象,应该使用"类名 对象名"的形式,而不是"类名 对象名()";

      2.对象的赋值其实和变量的赋值差不多,也是用赋值运算符=进行的,只不过进行赋值的两个对象的类型必须相同,对象之间的赋值只是数据成员的赋值,而不对成员函数赋值;

    #include "stdafx.h"
    #include <iostream>

    usingnamespace std;

    class Kid
    {
    private:
    int age;
    char*name;
    char*sex;
    public:
    Kid(int age,char*name,char*sex);
    Kid(){ };
    ~Kid();
    void showKid();
    };


    Kid::Kid(int age,char*name,char*sex)
    {
    Kid::age=age;
    Kid::name=newchar[strlen(name)+1];
    strcpy(Kid::name,name);
    Kid::sex=newchar[strlen(sex)+1];
    strcpy(Kid::sex,sex);
    }

    Kid::~Kid()
    {
    cout<<"dispose object kid"<<endl;
    delete []name;
    delete []sex;
    }

    void Kid::showKid()
    {
    cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;
    }

    int main()
    {
    Kid kid(10,"rookie_j","男"),kid2;
    kid.showKid();

    kid2=kid;
    kid2.showKid();

    return0;
    }

    结果:

      拷贝构造函数是一种特殊的构造函数,其形参是类对象的引用。它主要用于在建立一个新的对象时,使用已经存在的对象去初始化这个新对象。拷贝构造函数也是构造函数,所以函数名必须与类名相同,参数只有一个就是同类对象的引用,每个类必须要有一个拷贝构造函数。如果程序员自己不定义拷贝构造函数,系统会自动产生一个默认拷贝构造函数。调用拷贝构造函数的形式有代入法:类名 对象2(对象1)和赋值法:类名 对象2=对象1;

    #include "stdafx.h"
    #include <iostream>

    usingnamespace std;

    class Kid
    {
    private:
    int age;
    char*name;
    char*sex;
    public:
    Kid(int age,char*name,char*sex);
    Kid(const Kid &kid);
    ~Kid();
    void showKid();
    };


    Kid::Kid(int age,char*name,char*sex)
    {
    Kid::age=age;
    Kid::name=newchar[strlen(name)+1];
    strcpy(Kid::name,name);
    Kid::sex=newchar[strlen(sex)];
    strcpy(Kid::sex,sex);
    }

    Kid::Kid(const Kid &kid)
    {
    Kid::age=kid.age*2;
    Kid::name=newchar[strlen(kid.name)+1];
    strcpy(Kid::name,kid.name);
    Kid::sex=newchar[strlen(kid.sex)];
    strcpy(Kid::sex,kid.sex);
    }

    Kid::~Kid()
    {
    cout<<"dispose object kid"<<endl;
    delete []name;
    delete []sex;
    }

    void Kid::showKid()
    {
    cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;
    }

    int main()
    {
    Kid kid(10,"rookie_j","男");
    kid.showKid();

    Kid kid2(kid);
    kid2.showKid();

    Kid kid3=kid2;
    kid3.showKid();

    return0;
    }

    结果:

      同样的默认的拷贝构造函数:复制出与源对象的数据成员的值一样的新对象。调用拷贝构造函数的3种情况:(1)Kid kid2(kid1)或Kid kid2=kid1;(2)函数的形参是类的对象:fun(Kid kid){kid.showKid();}; int main(){Kid kid(10,"Rookie_j","男");fun(kid);return 0;};(3)函数返回值为类的对象:Kid fun(){Kid kid(10,"Rookie_j","男"); return kid;} int main(){ Kid kid; kid=fun();kid.showKid();return 0;};

      3.最后还是一样用一个实例来总结一下今天所说的内容(开发工具:vs2010):

  • 相关阅读:
    安卓开发学习——事件机制
    安卓开发学习——消息机制与异步任务
    安卓存储学习
    scrollTop, pageYOffset, scrollY 以及offsetTop 的区别
    BFC与IFC概念理解+布局规则+形成方法+用处
    JavaScript的作用域、作用域链和执行期上下文
    深入理解javascript原型和闭包系列
    【剑指Offer】剑指offer题目汇总
    CSS文件加载方式: @import 和 <link>
    jquery跨域:$.ajax 和$.getJSON
  • 原文地址:https://www.cnblogs.com/honeybusybee/p/5281081.html
Copyright © 2011-2022 走看看