HOUR 14 Calling Advanced Functions
默认参数
函数重载和默认参数函数会达到同样的效果。默认参数写起来简单,理解起来难。
默认构造参数有个缺点是,当参数不断增加的时候,理解起来会有点困难。
#include <QCoreApplication> #include <iostream> class Rectangle { public: Rectangle(int aWidth, int aHeight); ~Rectangle() {} void drawShape(int aWidth, int aHeight, bool useCurrentValue = false) const; private: int width; int height; }; Rectangle::Rectangle(int aWidth, int aHeight) { width = aWidth; height = aHeight; } void Rectangle::drawShape(int aWidth, int aHeight, bool useCurrentValue) const { int printWidth; int printHeight; if (useCurrentValue == false) { printHeight = aHeight; printWidth = aWidth; } else { printHeight = height; printWidth = width; } for(int i = 0; i < printHeight; i++) { for(int j = 0; j < printWidth; j++) std::cout << '*'; std::cout << std::endl; } } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Rectangle box(10, 2); box.drawShape(5, 5); box.drawShape(5, 5, true); return a.exec(); }
构造函数重载:构造函数的创建分为两个阶段
- 初始化阶段
- 函数体阶段
Tricycle::Tricycle() : speed(5), wheelSize(12) { //other statements }
构造函数后面的冒号表示要开始初始化了, 函数体完成其他的赋值操作。
常量变量和引用必须在初始化的时候给定值,所以类内的引用、const等必须用这种技术
Copy Constructor
编译器会自动创建复制构造函数,每次发生复制时候调用。
当向一个类中传值的时候,就会调用复制构造函数创建一个临时复制的对象。
复制构造函数只接受一个参数——指向同一类对象的引用,由于复制不会改变传入的对象,所以最好定义为const类型的,例如
Tricycle(const Tricycle &trike);
#include <QCoreApplication> #include <iostream> using namespace std; class Tricycle { public: Tricycle(); ~Tricycle(); // Tricycle(const Tricycle& rhs); void setSpeed(int newSpeed) { *speed = newSpeed;} int getSpeed() const; void pedal(); void brake(); private: int *speed; }; void Tricycle::pedal() { setSpeed(*speed + 1); cout << "\nPedalling " << getSpeed() << "mph" << endl; } void Tricycle::brake() { setSpeed(*speed - 1); cout << "\nBraking " << getSpeed() << "mph" << endl; } Tricycle::Tricycle() { speed = new int; *speed = 5; } /*Tricycle::Tricycle(const Tricycle &rhs) { speed = new int; *speed = rhs.getSpeed(); } */ Tricycle::~Tricycle() { delete speed; speed = NULL; } int Tricycle::getSpeed() const {return *speed;} int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); cout << "creating bike named wichita " << endl; Tricycle wichita; wichita.pedal(); cout << "creating bike named dollas " << endl; Tricycle dallas(wichita); cout << "wichita's speed: " << wichita.getSpeed() << endl; cout << "dallas's speed: " << dallas.getSpeed() << endl; // change the original speed to see if the copied object // also changed automatly wichita.setSpeed(99); cout << "wichita's speed: " << wichita.getSpeed() << endl; cout << "dallas's speed: " << dallas.getSpeed() << endl; return a.exec(); }

改变原始对象的speed,新对象的speed也被改变,这是因为他们指向同一片区域。如果把复制构造函数定义一下,新对象创建时候,自己在heap上开辟自己专用的内存空间,这样改变wichita的数据,就不会影响到dallas了。
复制构造函数传入的参数是rhs,表示right-hand side,这是复制构造函数一种比较通用的命名法。


深复制和浅复制通过这两个图就看出来了。
Summary
- 构造函数可以重载,参数的数目类型决定调用哪个。
- 构造函数可以有默认参数
默认复制构造函数,在发生复制时,把所有变量都复制一遍。当类内有指向heap的指针的时候,就很危险了。因为如果原对象生命周期到了,复制构造的对象依然指向那块内存,可不可怕。
解决这个问题可以自己写复制构造函数,不要编译器代劳。记住,复制构造函数只接受一个参数——将要被复制到对象。
Q&A
Q. 有了函数重载,为何还要有默认参数?
A. 默认参数就管理一个函数。只升级一个函数,而不升级另一个函数,是一种常见的错误类型。
Q. 有了默认参数,为毛要有 函数重载?
A. 函数重载支持不同类型参数重载,默认参数只能修改number
Q. 构造函数的初始化列表和函数体中,如何分配初始化成员?
A. 能放在初始化列表的,就不要放在函数体内。诸如计算啦,std::cout这种啦,就放在函数体里吧
Q. 重载的函数可以有默认参数吗?
A. 可以,重载牛逼,默认参数牛逼。结合起来牛逼牛逼。前提是参数类型和数量,不要让编译器感觉二义性!

浙公网安备 33010602011771号