Questions:
(1)空类真的是empty class吗?( Is empty class a empty body class?)
(2)copy构造函数?
(3)在什么情况下编译器会拒绝为class生成operator=?
Answers:
(1)空类真的是empty class吗?( Is empty class a empty body class?)
如果定义以下这个类:
这个Empty类的类体是空的,它真的是一个empty class吗?当然不是!
当C++处理过它之后,编译器就会为它声明一个copy构造函数、一个copy assignment重载操作符和一个析构函数,此外还有一个default构造函数。所有这些函数都是public且inline的。
因此,以上的类定义等价于以下类定义:
class Empty
{
public:
Empty() { ... } //default构造函数
Empty(const Empty& rhs) { ... } //copy构造函数
~Empty() { ... } //析构函数
Empty& operator=(const Empty& rhs) { ... } //copy assignment操作符
};
需要注意的是:编译器产出的析构函数是个non-virtual,除非这个class的base class自身声明有virtual析构函数(这种情况下这个函数的虚属性virtualness主要来自base class)。至于copy构造函数和copy assignment操作符,编译器创建的版本只是单纯地将来源对象的每一个non-static成员变量拷贝到目标对象。
(2)copy构造函数?
拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。例如:类X的拷贝构造函数的形式为X(X& x)。
当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:
a、一个对象以值传递的方式传入函数体
b、一个对象以值传递的方式从函数返回
c、一个对象需要通过另外一个对象进行初始化。
如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝。
默认Copy构造函数中如果成员变量是内置类型,则按bit拷贝,如果成员变量不是内置类型,调用成员变量所属类型的Copy构造函数。
如下自定义copy构造函数的例子:
#include<iostream>
using namespace std;
#include <stdio.h>
class point
{
private:
int m_x,m_y;
public:
point()
{
m_x = 0;
m_y = 0;
}
point(int x, int y)
{
m_x = x;
m_y = y;
}
point(const point& p)
{
m_x = p.m_x;
m_y = p.m_y;
cout<<"copy constructor is called!"<<endl;
}
static point reverse(const point& p)
{
point p1;
p1.m_x = p.getY();
p1.m_y = p.getX();
return p1;
}
int getX() const
{
return m_x;
}
int getY() const
{
return m_y;
}
void print()
{
cout<<m_x<<" "<<m_y<<endl;
}
};
int main()
{
point p(1, 2);
point p1(p); //initialize p1 with p
point p2 = point::reverse(p1);
p2.print();
return 0;
}
point类定义了一个copy构造函数,在main函数中,首先生成一个对象p,这会调用带参构造函数,然后用p初始化p1,这会调用一次copy构造函数,然后又调用reverse,以p1为实参,将p1的m_x和m_y交换,返回一个point对象,结果赋值给p2,这会调用两次copy构造函数,第一次是在参数传递的时候,第二次是在返回对象的时候。运行结果如下图:
(3)在什么情况下编译器会拒绝为class生成operator=?
只有当生出的代码合法且有适当机会证明它有意义,编译器才会自动生成赋值构造函数,万一两个条件有一个不符合,编译器会拒绝为class生成operator=。以下情况:
a、如果类包括引用成员或者const成员,编译器拒绝生成Copy赋值操作符。
因为”C++不允许让reference改指向不同对象!”,引用的变量值一经初始化就不可以再修改其指向,同样const变量的值一经初始化就不可以再改变!
b、如果某个base classes将copy assignment操作符声明为private,编译器将拒绝为其derived classes生成一个copy assignment操作符。
因为编译器为derived classes所生成的copy assignment操作符想象中可以处理base class的内容,但它当然无法调用derived class无权调用的private成员函数。