<一>
#include <iostream>
#include <string>
class Stock
{
public:
/*explicit*/ Stock(const std::string& company) : _company(company), _share(0), _val(0.0) {}
Stock() : _company(""), _share(0), _val(0.0) {}
Stock(const std::string& company, long share, double val)
: _company(company), _share(share), _val(val) {}
private:
std::string _company;
long _share;
double _val;
};
int main(){
Stock food = Stock("hello",12,20.5);
Stock food1("hello",12,20.5);
Stock food2 = std::string("hi");
std::cout <<"food : "<<&food<<", food1 : "<<&food1<<", food2 : "<<&food2<< std::endl;
return 0;
}
显式调用构造函数
显式调用构造函数意味着直接使用构造函数的参数来初始化对象。这通常在创建对象时发生,无论是通过声明一个变量还是通过使用new
关键字动态分配内存。
Stock food = Stock("hello",12,20.5);
Stock food1("world",13,2.5);
每次创建类对象(甚至使用new动态分配内存)时,C++都使用类构造函数。下面是将构造函数与new一起使用的方法:
Stock *pstock = new Stock("google",15,22.5);
隐式调用构造函数
隐式调用构造函数发生在将一个对象初始化为另一个对象,或者通过省略括号直接使用赋值语句时。对于构造函数,如果它只有一个参数(或所有参数除了一个都有默认值),那么它还可以作为转换构造函数,允许从一个类型隐式转换为对象类型。
Stock food = std::string("hi");
当使用explicit
关键字时,阻止了隐式转换,要创建Stock
对象,必须显式调用构造函数;
但如果没有explicit
关键字,上述代码将隐式调用Stock(const string& company)
构造函数。
<二>
class A
{
};
如果在编写类时没有显示的写出其构造函数,拷贝构造函数,析构函数,以及重载赋值操作符,编译器会在编译代码时,会为该类加上这些。
其形式大致如下:
class A
{
A()
{
}
A& operator =(const A& a)
{
memcpy(this, &a, sizeof(A)); //此处可能用问题,仅为表明不是浅拷贝
return *this;
}
A(const A& a)
{
*this = a; //调用了赋值重载函数
}
~A() // 注意在析构函数前不会加上virtual关键字
{
}
};
下面给出一些示例,注释部分说明了函数调用的情况:
void f()
{
A a; // A()构造函数被调用
A b(a); // A(const A& a)构造函数被调用
A c = a; // A(const A& a)构造函数被调用
b = c; // A& operator = (const A& a)赋值操作符重载函数被调用
}
// 离开f()函数之前,a,b,c的析构函数被调用,释放资源
A c = a;
这句代码实际调用的是拷贝构造函数,而非赋值函数。
因此,我们可以构造出这样的代码。
class A
{
private:
int *m_data;
std::string ss;
public:
A()
{
m_data = NULL;
}
A(int n)
{
m_data = NULL;
if (n>0)
m_data = new int[n];
}
A& operator =(const A& a)
{
memcpy(this, &a, sizeof(A));
return *this;
}
virtual ~A()
{
if (NULL!=m_data)
{
delete [] m_data;
m_data = NULL;
}
}
};
int main()
{
A a = 3; // 将整数3赋值给一个对象
return 0;
}
将整数3赋值给一个A类型对象a,然而以上代码可以编译通过。 -- 有点不合常理
这是由于“单参数构造函数”被自动型别转换(这是一个隐式转换)。
可以通过explicit关键字,阻止“以赋值语法进行带有转型操作的初始化”。如下所示:
class A
{
private:
int *m_data;
std::string ss;
public:
A()
{
m_data = NULL;
}
explicit A(int n)
{
m_data = NULL;
if (n>0)
m_data = new int[n];
}
A& operator =(const A& a)
{
memcpy(this, &a, sizeof(A));
return *this;
}
virtual ~A()
{
if (NULL!=m_data)
{
delete [] m_data;
m_data = NULL;
}
}
};
int main()
{
// A a = 3; // 编译无法通过
A b(3); // 可以编译通过
return 0;
}