2019-04-08 C++学习笔记之类和对象(中)

参考资料:《21天学通C++》

对象

对象概述

对象是现实世界中的实体,其一般具有以下特征:

  • 每个对象都有一个用于与其他对象相区别的名字。
  • 具有某些特征,称为属性或状态。
  • 有一组操作,每一个操作决定对象的一种行为,即对象能干什么。
  • 对象的状态只能被自身行为所改变。
  • 对象之间以消息传递的方式相互通信。

注意:上述特征在面向对象程序设计中分别被抽象为对象名属性事件方法消息。这是面向对象程序设计的基础。

对象数组

对象数组是指以数组元素为对象的数组,该数组中若干个元素必须是同一个类的若干对象。对象数组的定义、赋值和引用与普通数组一样,只是数组的元素与普通数组不同,它是同类的若干个对象。

一般来说,定义对象数组的格式如下:

类名 数组名[大小]

其中参数说明如下:

  • 类名:指出该数组元素是属于该类的对象。
  • 数组名:定义该对象数组的名称,它必须是C++的标识符。
  • 大小:方括号内的数字给出某一维的元素个数。一维对象数组只有一个方括号,二维对象数组要有两个方括号等。

例如,下列语句定义了一个一维对象数组:

Cbook dates[7];

上述语句表明dates是一维对象数组名,该数组有7个元素,其中的对象属于Cbook类,也即每个元素都是类Cbook的对象。

与普通数组类似,对象数组可以被赋初值,也可以被赋值。

例1 对象数组的定义和赋值

#include <iostream>
using namespace std;

class DATE {                        //声明类
public:                             //公有成员
    DATE(int m, int d, int y);
    void print();
private:                            //私有成员
    int month, day, year;
};

DATE dates[4] = {DATE(7, 7, 2001), DATE(7, 8, 2001), DATE(7, 9, 2001), DATE(7, 10, 2001)};  //初始化

DATE :: DATE(int m, int d, int y) { //定义成员函数(构造函数)
    month = m;
    day = d;
    year = y;
}

void DATE :: print() {              //定义成员函数
    cout << month << "\t" << day << "\t" << year << endl;
}

void main() {
    int i;
    for(i = 0; i < 4; i++)
        dates[i].print();           //调用对象的print函数
}

输出:

7       7       2001
7       8       2001
7       9       2001
7       10      2001

构造函数

构造函数的概念

注意:在类中定义成员变量时,不能给这些变量赋初值。

构造函数是在类中定义的一种特殊的函数,其函数名称与类的名称相同。

构造函数的主要功能是为对象分配空间,也可以用来为类成员变量赋初值,因此构造函数没有返回类型,也没有return语句。

构造函数具有以下性质:

  • 构造函数的名字必须与类的名字相同
  • 构造函数的参数可以是任何数据类型,但它没有返回值,不能为它定义返回类型。
  • 对象定义时,编译系统自动调用构造函数完成对象内存空间的分配和初始化工作。
  • 构造函数是类的成员函数,具有一般成员函数的所有性质,可以访问类的所有成员,可以是内联函数,可以带参数表,可以有默认的形参值,也可以重载。

构造函数的声明和定义

构造函数的声明和定义与普通成员函数的声明和定义类似。

例如,下面的语句给出了一个类的声明和定义,其中包含了构造函数的声明和定义:

class complex {
private:
    double real, imag;              //定义复数的实部和虚部
public:
    complex(double r, double i) {   //声明构造函数,其名字与类名相同
        real = r;
        imag = I;                   //初始化私有数据成员imag和real
    }
    void disp() {
        cout << real << "+" << imag << "i" << endl;
    }
};

上面的语句定义了一个类complex,其包含两个私有成员变量,在公有成员中,其包含了两个成员函数:complex()函数和disp()函数。其中,complex函数为构造函数,其函数名与类名相同,并且带有两个参数。

此外,构造函数可以在类中声明,在外部定义。

例如,上述上明定义的类可以改写成以下形式:

class complex {
private:
    double real, imag;                      //定义复数的实部和虚部
public:
    complex(double r, double i);            //声明构造函数
    void disp() {
        cout << real << "+" << imag << "i" << endl;
    }
};
complex :: complex(double r, double i) {    //定义构造函数
    real = r;
    imag = I;
}

注意:在类的外部定义构造函数时,需要在函数前增加类名和域运算符。

一般都需要给类定义构造函数,如果没有定义,编译系统就会自动生成一个默认的构造函数,这个默认的构造函数不带任何参数,只能给对象开辟一个存储空间,不能为对象赋初值。

构造函数的调用

在定义了构造函数之后就可以对其进行调用了。一般来说,在定义对象的同时会自动调用构造函数,不需要显式调用。构造函数的调用格式为:

类名 对象名(实参表)

例7 构造函数的调用

#include <iostream>
using namespace std;

class complex {
private:
    double real, imag;                      //定义复数的实部和虚部
public:
    complex(double r, double i);            //声明构造函数
    void disp() {                           //声明成员函数
        cout << real << "+" << imag << "i" << endl;
    }
};

complex :: complex(double r, double i) {    //定义构造函数
    real = r;                               //成员变量初始化
    imag = i;
}

int main(void) {
    complex op1(1.5, 3.0);                  //创建对象
    op1.disp();
    return 0;                               //调用类的成员函数
}

输出:

1.5+3i

上述代码中,首先定义了类complex及其构造函数,在类外定义了该构造函数。在main()函数中,没有直接调用构造函数,而是在声明了对象op1的同时系统自动调用了该构造函数。

不带参数的构造函数

构造函数也可以不带参数。

例8 不带参数的构造函数

#include <iostream>
using namespace std;

class myclass {                 //定义类
private:                        //定义私有成员
    int a;
public:
    myclass();                  //声明不带参数的构造函数
    void disp() {
        cout << "a * a = " << a << endl;
    }
};

myclass :: myclass() {          //定义构造函数
    cout << "initialized.\n";
    a = 10;                     //给变量初始化
}

int main(void) {
    myclass s;                  //创建对象,执行构造函数
    s.disp();                   //调用成员函数
    return 0;
}

输出:

initialized.
a * a = 10

上述代码中,定义了一个类myclass,在类中声明了该类的构造函数myclass()。该构造函数无参数,在类外定义该构造函数,输出提示信息“initialized”并给私有变量赋初值0。

注意:不带参数的构造函数的初始化是固定的,如果希望在建立对象时通过参数初始化数据成员,应使用带参数的构造函数。

带有默认参数的构造函数

在实际应用中,有些构造函数的参数值通常是不变的,只有在特殊情况下才改变它的值,这时可以将构造函数定义成带默认参数的值的构造函数。此时在定义对象时可以不指定实参,用默认参数值来初始化数据成员。

例9 带默认参数的构造函数

#include <iostream>
#include <math.h>
using namespace std;

class complex {
private:
    double real, imag;
public:
    complex(double real = 0.0, double imag = 0.0);  //声明带有默认参数的构造函数
    double abscomplex();
};

complex :: complex(double r, double i) {            //定义构造函数
    real = r;                                       //成员初始化
    imag = i;
}

double complex :: abscomplex() {                    //定义成员函数
    double n;
    n = real * real + imag * imag;
    return sqrt(n);                                 //返回平方根值
}

int main(void) {
    complex ob1;                                    //创建对象ob1
    complex ob2(1.1);                               //创建对象ob2
    complex ob3(1.1, 2.2);                          //创建对象ob3

    cout << "abs of complex ob1 = " << ob1.abscomplex() << endl;
    cout << "abs of complex ob2 = " << ob2.abscomplex() << endl;
    cout << "abs of complex ob3 = " << ob3.abscomplex() << endl;

    return 0;
}

输出:

abs of complex ob1 = 0
abs of complex ob2 = 1.1
abs of complex ob3 = 2.45967

上述代码中,对象ob1在定义时没有传递任何参数,所以real和imag均去构造函数的默认值初始化,real和imag均为0.0。对象ob2在定义时传递了一个参数,按顺序传递给了第一个形参real,第二个形参imag取默认值,所以real为1.1,imag为0.0。对象ob3在定义时传递了两个参数,所以real为1.1,imag为2.2。

注意:创建对象调用的构造函数是否带参数,其创建的对象对成员变量的初始化程度是不一样的。

构造函数的重载

C++允许对构造函数的重载,即可以定义多个参数及参数类型不同的构造函数,用多种方法对对象初始化。

例10 构造函数的重载

#include <iostream>
using namespace std;

class point {
private:
    double fx, fy;
public:
    point();                                    //声明不带参数的构造函数
    point(double x, double y);                  //声明带两个参数的构造函数
    void showpoint();
};

point :: point() {                              //定义不带参数的构造函数
    fx = 0.0;                                   //成员初始化
    fy = 0.0;
}

point :: point(double x, double y = 5.5) {      //定义带两个参数的构造函数
    fx = x;                                     //成员初始化
    fy = y;
}

void point :: showpoint() {                     //定义成员函数
    cout << fx << "\t" << fy << endl;
}

int main(void) {
    point p1;                                   //用构造函数point创建对象
    cout << "The fx and fy of p1: ";
    p1.showpoint();

    point p2(1.0);                                   //用构造函数point(double x, double y = 5.5)创建对象
    cout << "The fx and fy of p2: ";            //fy用默认值5.5初始化
    p2.showpoint();

    point p3(1.1, 2.0);
    cout << "The fx and fy of p3: ";            //用构造函数point(double x, double y = 5.5)创建对象
    p3.showpoint();                             //fy被重新赋值为2.0

    return 0;
}

输出:

The fx and fy of p1: 0    0
The fx and fy of p2: 1    5.5
The fx and fy of p3: 1.1    2

上述代码中,类point中声明了两个构造函数:point()和point(double x, double y)。在main()函数中声明对象时,系统自动调用相应的构造函数,如在point p1;语句中声明p1对象时,调用的是point()构造函数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,914评论 2 9
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,557评论 1 51
  • C++文件 例:从文件income. in中读入收入直到文件结束,并将收入和税金输出到文件tax. out。 检查...
    SeanC52111阅读 2,918评论 0 3
  • 一曲新歌酒一杯,那年亭台群英会。 夕阳西下不知回。 无可奈何冬季去,似曾相识春归来。 东钱湖畔独徘徊。
    三章半阅读 358评论 0 0
  • 你必须非常努力,才能看起来毫不费力。
    zruibin阅读 239评论 0 1