C++使用默认参数的构造函数

我们可以想象一个这样的场景:某一天书店整理库存,发现了一些非常老的书,为了尽快清空库存,店主想了一下,决定开展一个大甩卖活动,所有的这些书全部以五美元的价格出售。此时如果需要尽快将这些书的信息录入到书店的书单中,为了方便,我们可以在 book 类中添加一个带默认参数的构造函数。

【例 1】默认带参构造函数示例:
#include<iostream>
using namespace std;

class book
{
public:
    book(){}
    book(char* a, double p = 5.0);
    void display();
private:
    double price;
    char * title;
};

book::book(char* a, double p)  //在定义函数的时候可以不指定默认参数
{
    title = a;
    price = p;
}

void book::display()
{
    cout<<"The price of "<<title<<" is $"<<price<<endl;
}

int main()
{
    book Harry("Harry Potter", 49.9);
    Harry.display();
    book Gone("Gone with the Wind");
    Gone.display();
    return 0;
}
在本例中,book 类中的带参构造函数book(char* a, double p = 5.0);将价格设置为 5.0,如此一来 p 就被设置成为一个默认参数,如果在创建对象的时候,没有传递实参给该参数 p,则该参数会被默认设置为 5.0。

在例 1 的主函数中我们可以看到,Harry 对象创建时传递了两个实参 "Harry potter" 和 49.9,而 Gone 对象则只是传递了一个实参 "Gone with the Wind" 用于初始化 title,此时 price 就会被用默认参数初始化为 5.0。

程序运行结果如下:

The price of Harry Potter is $49.9
The price of Gone with the Wind is $5.0

需要说明的是带默认参数的构造函数,其默认参数必须置于参数列表的结尾。如果例 1 中带参构造函数book(char* a, double p = 5.0);被声明成book(double p = 5.0, char* a);则是无法通过编译的,因为默认参数不在参数列表的结尾。

虽然带参数的构造函数会给我们初始化带来一定便利,但糟糕的是它也会给构造函数的调用带来歧义。

【例 2】默认带参构造函数所带来的歧义:
#include<iostream>
using namespace std;
   
class book
{
public:
    book(){}
    book(char* a, double p = 5.0);
    book(char *a);
    void setprice(double a);
    double getprice();
    void settitle(char* a);
    char * gettitle();
    void display();
private:
    double price;
    char * title;
};

book::book(char* a, double p)  //在定义函数的时候可以不指定默认参数
{
    title = a;
    price = p;
}

book::book(char *a)
{
    title = a;
}

void book::display()
{
    cout<<"The price of "<<title<<" is $"<<price<<endl;
}
    int main()
{
    book Harry("Harry potter", 49.9);
    Harry.display();
    book Gone("Gone with the Wind"); //compile error
    Gone.display();
    return 0;
}
在本例中有三个构造函数,一个是默认构造函数,两个带参构造函数,其中一个为带有默认参数的构造函数。

在主函数中,通过 book 类创建 Harry 对象没有问题,此时创建对象只能调用book(char* a, double p = 5.0);构造函数。创建 Gone 对象时则有问题了,此时我们创建对象有两个与之匹配的构造函数可以调用,分别是book(char *a);book(char* a, double p = 5.0);,此时该调用哪一个呢?无法得知,编译器只能报错了。

出现这种情况我们只能极力去避免了,通常而言,在设计类的构造函数的时候最好不要同时是用构造函数的重载和带参数的构造函数,以避免上述问题。