构造函数分为默认构造函数(default constructor)和非默认构造函数(constructor)
(假设有类Stock)
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot() { total_val = shares * share_val; }
public:
Stock(); // default constructor
Stock(const std::string & co, long n = 0, double pr = 0.0);
~Stock(); // noisy destructor
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show();
};
1. 非默认构造函数
构造函数没有返回值(不是void,它根本没有返回类型),函数名与类名相同。
非默认构造函数需要用户来指定初始值来初始化对象,因此需要设置形参来接受用户给的值
Stock::Stock(const std::string & co, long n, double pr)
{
std::cout << "Constructor using " << co << " called\n";
company = co;
if (n < 0)
{
std::cout << "Number of shares can't be negative; "
<< company << " shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
2. 默认构造函数(default constructor)
未提供显式初始值时,用来创建对象的构造函数。
默认构造函数会在类没有任何构造函数时由编译器提供,一旦程序员提供了非默认构造函数,就必须同时提供默认构造函数给这个类,否则会在初始化对象(仅初始化对象,不初始化对象中的任何成员)时出现错误。
声明构造函数有两种方式:
①给已有构造函数的所有参数提供默认值(已提供非默认构造函数)
Stock(const string & co="Error",int n=0, double pr =0.0);
②通过函数重载来定义一个没有参数的构造函数(已提供非默认构造函数)(这个默认构造函数不执行操作,只为了通过编译)
Stock();
TIPS:
1.构造函数有隐式调用和显式调用:
Stock food = Stock("ABC",250,1.25);//显式调用 calls it explicitly
Stock food("ABC",250,1.25)//隐式调用 calls it implicitly
(注意,这里的显式调用是一种独特的语法,我开始以为是创建了一个无名对象副本再利用默认的重载赋值运算符将无名对象副本中的内容非深度复制给food,询问chatgpt后它说这是一种特殊语法)
2.
C++为构造函数提供了成员初始化列表(仅有构造函数有这个语法!!!),它可以在对象创建之后,调用构造函数代码块之前,初始化对象中的成员,语法如下
Class::Class(int n,int m):member1(n),member2(0),member3(n*m+1)
{
......
}
这个构造函数将在生成Class类相应的对象时将member1、2、3赋值为n,m,n*m+1,之后才执行代码块中的内容。
这个特殊语法在类中有const数据成员时是必不可少的,因为const 成员不允许在被创建之后修改它的值;
并且在类继承中,这个语法被用于派生类的构造函数中:派生类构造函数通过成员初始化列表将基类信息传递给基类构造函数(同const数据成员需要用这个语法的原理一样,派生类相应对象在构造函数开始执行代码块之后实际上已经生成了其中的基类对应的数据成员,而在派生类的构造函数中没有权限修改基类的数据成员,因此需要用到成员初始化列表,在代码块之前,创建基类数据成员的同时就将其初始化)