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();
}

 

构造函数重载:构造函数的创建分为两个阶段

  1. 初始化阶段
  2. 函数体阶段
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. 可以,重载牛逼,默认参数牛逼。结合起来牛逼牛逼。前提是参数类型和数量,不要让编译器感觉二义性!

 

 

 

 

posted @ 2018-03-21 09:46  一只大公鸡  阅读(128)  评论(0)    收藏  举报