本文共 4901 字,大约阅读时间需要 16 分钟。
假设有这么一个类
#includeclass Stock // class declaration{ private: std::string company; long shares; double share_val; double total_val; void set_tot() { total_val = shares * share_val; }public: void acquire(const std::string & co, long n, double pr); void buy(long num, double price); void sell(long num, double price); void update(double price); void show();}; // note semicolon at the end
C++的目标之一是让使用类对象就像使用标准类型一样,然而,到现在为止,本章提供的代码还
不能让您像初始化int或结构那样来初始化 Stock对象。 也就是说,常规的初始化语法不适用于类型Stock:int year = 2001; // valid initializationstruct thing { char *pn; int m:};thing amabob = { "wodge", -23}; // valid initializationStock hot = { "sukie's Autos, Inc ", 200, 50.25 }; //NO! compile error
不能像上面这样初始化 Stock对象的原因在于,数据部分的访问状态是私有的,这意味着程序不能直接访问数据成员。您已经看到,程序只能通过成员函数来访问数据成员,因此需要设计合适的成员函数,才能成功地将对象初始化(如果使数据成员成为公有,而不是私有,就可以按刚才介绍的方法初始化类对象,但使数据成为公有的违背了类的一个主要初衷:数据隐藏)。
一般来说,最好是在创建对象时对它进行初始化。例如,请看下面的代码:Stock gift;gift.buy(10, 24.75);
就 Stock类当前的实现而言,gift对象的 company成员是没有值的。类设计假设用户在调用任何其他成员函数之前调用 acquire(),但无法强加这种假设。
避开这种问题的方法之一是在创建对象时,自动对它进行初始化。 为此,C++提供了一个特殊的成员函数一类构造函数,专门用于构造新对象、将值赋给它们的数据成员。更准确地说,C++为这些成员函数提供了名称和使用语法,而程序员需要提供方 法定义。 名称与类名相同。例如, Stock类一个可能的构造函数是名为 Stock()的成员函数。构造函数的原型和函数头有一个有趣的特征一一虽然没有返回值,但没有被声明为void类型。实际上,构造函数没 有声明类型。现在需要创建 Stock的构造函数。
由于需要为 Stock对象提供3个值,因此应为构造函数提供3个参数(第4个值, total_val成员,是根据 shares和 share_val计算得到的,因此不必为构造函数提供这个值。) 程序员可能只想设置 company成员,而将其他值设置为0:这可以使用默认参数来完成(参见第8章)。 因此原型如下所示:// constructor prototype with some default argumentsStock(const string &co, long n=0, double pr =0.0);
第一个参数是指向字符串的指针,该字符串用于初始化成员 company. n和p参数为 shares和share_val成员提供值。注意,没有返回类型。原型位于类声明的公有部分。
下面是构造函数的一种可能定义Stock::Stock(const string & co, long n, double pr){ company = co; if (n < 0) { std::cerr <<"Number of shares can't be negative;" << company << "shares set to 0. \n"; shares =0; } else { shares = n; } share_val = pr; set_tot();}
上述代码和本章前面的函数 acquire()相同。
区别在于,程序声明对象时,将自动调用构造函数C++提供了两种使用构造函数来初始化对象的方式。
第一种方式是显式地调用构造函数:Stock food = Stock("World Cabbage", 250, 1.25);
这将food对象的 company成员设置为字符串“ World Cabbage’”,将 shares成员设置为250,依此类推
另一种方式是隐式地调用构造函数:Stock garment("Furry Mason", 50, 2.5);
这种格式更紧凑,它与下面的显式调用等价
Stock garment = Stock("Furry Mason", 50, 2.5);
每次创建类对象(甚至使用new动态分配内存)时,C++都使用类构造函数。下面是将构造函数与new起使用的方法:
Stock *pstock= new Stock("Electroshock Games", 18, 19.0);
这条语句创建一个 Stock对象,将其初始化为参数提供的值,并将该对象的地址赋给 stock指针。在这种情况下,对象没有名称,但可以使用指针来管理该对象。我们将在第11章进一步讨论对象指针。
构造函数的使用方式不同于其他类方法。一般来说,使用对象来调用方法:stock1.show(); //stock1 object invokes show() method
但无法使用对象来调用构造函数,因为在构造函数构造出对象之前,对象是不存在的。因此构造函数被用来创建对象,而不能通过对象来调用。
构造函数是一种特殊的类成员函数,在创建类对象时被调用。
构造函数的名称和类名相同,但通过函数重载,可以创建多个同名的构造函数,条件是每个函数的特征标(参数列表)都不同。另外,构造函数没有声明类型。通常,构造函数用于初始化类对象的成员,初始化应与构造函数的参数列表匹配。例如,假设Bozo类的构造函数的原型如下:
Bozo(const char * fname,const char * lname); // constructor prototype
则可以使用它来初始化新对象: Bozo bozetta = bozo("Bozetta","Biggens"); // primary form
Bozo fufu("Fufu","O'Dweeb"); // short form
Bozo *pc = new Bozo("Popo","Le Peu"); // dynamic object
如果编译器支持C++11,则可使用列表初始化: Bozo bozetta = { "Bozetta","Biggens"}; //C++11Bozo fufu("Fufu","O'Dweeb") // C++11;Bozo *pc = new Bozo{ "Popo","Le Peu"); //C++11
如果构造函数只有一个参数,则将对象初始化为一个与参数的类型相同的值时,该构造函数将被调用。例如,假设有这样一个构造函数原型:
bozo(int i)
则可以使用下面的任何一种形式来初始化对象: Bozo dribble =bozo(44) // primary formBozo roon(66); // secondary formBozo tubby = 32; // special form for one-argument constructors
实际上,第三个示例是新内容,不属于复习内容,但现在正是介绍它的好时机。第11章将介绍一种关闭这项特性的方式,因为它可能带来令人不愉快的意外。
警告:接受一个参数的构造函数允许使用赋值语法将对象初始化为一个值:Classname object = value;
这种特性可能导致问题,但正如第11章将介绍的,可关闭这项特性。 constructor.cpp
#include/* author:梦悦foundation 公众号:梦悦foundation 可以在公众号获得源码和详细的图文笔记*/using std::cout;using std::endl;class Bozo { public: int iVar; Bozo(int i) { cout << "i = " << i << endl; this->iVar = i; } void show();};void Bozo::show(){ cout << "iVar = " << this->iVar < 公众号:梦悦foundation---------------" << endl; Bozo dribble = Bozo(44); // primary form Bozo roon(66); // secondary form Bozo tubby = 32; // special form for one-argument constructors dribble.show(); roon.show(); tubby.show(); cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;}
运行结果:
meng-yue@ubuntu:~/MengYue/c++/object_class/02$ ./constructor---------------开始--->公众号:梦悦foundation---------------i = 44i = 66i = 32iVar = 44iVar = 66iVar = 32---------------结束--->公众号:梦悦foundation---------------meng-yue@ubuntu:~/MengYue/c++/object_class/02$
可以看到,直接给类实例赋值一个整数也是可以的。
默认构造函数没有参数,因此如果创建对象时没有进行显式地初始化,则将调用默认构造函数。
如果程序中没有提供任何构造函数,则编译器会为程序定义一个默认构造函数;否则,必须自己提供默认构造函数。对于未被初始化的对象,程序将使用默认构造函数来创建:
Bozo bubi;// use defaultBozo *pb = new Bozo; // use default
就像对象被创建时程序将调用构造函数一样,当对象被删除时,程序将调用析构函数。
每个类都只能有一个析构函数。析构函数没有返回类型(连void都没有),也没有参数,其名称为类名称前加上~
。例如,Bozo类的析构函数的原型如下: // class destructor~Bozo();
如果构造函数使用了new,则必须提供使用delete的析构函数。
转载地址:http://meyci.baihongyu.com/