构造函数语义

结论

在类没有提供默认构造、拷贝构造函数、拷贝赋值函数时,编译器会自动合成相应的函数;
编译器只在需要的时候合成编译器完成必要工作所需要的默认构造、拷贝构造、拷贝赋值函数
构造函数语义
一、合成的默认构造函数
  1. 合成时机:默认构造函数在被编译器需要的时候被合成;
  2. 功能:只执行编译器需要的行动;
  3. 具体说明
    1. 类中包含成员对象,且该成员对象的类有默认构造函数:编译器会合成一个默认构造函数,只执行必要的操作用来调用foo的默认构造,但是不会对str进行任何处理。
    2. 派生自带有默认构造函数的基类:
      [例] 同上
    3. 带有虚函数的类:
      编译器为了支持多态,会为每一个类安插一个虚表的指针,所以,会合成一个用于初始化虚函数表指针的默认构造;
      若已经定义了构造函数,编译器会对现有的构造函数进行扩充,用于虚函数表的初始化。
    4. 带有虚基类的类
      初始化虚基类的相关指针
  4. 额外说明:如果class A内含一个或一个以上的member class objects,那么class A的每一个constructor 必须调用每一个member classes 的 default constructor;编译期会扩张已存在的constructors,在其中安插一些代码,使得用户代码被执行之前,先调用必要的default constructors。
// 例
class Foo
{
    public:
    	Foo();
        ...
};
class Bar
{
    public:
        Foo foo;
        char* str;
        inline Bar():foo()
    	{
        	//编译器合成版本
    	}

    	Bar(Param p):foo()/*编译器添加,按照类中声明顺序进行初始化*/
    	{
        	//显示默认构造/带参构造
    	}
};
二、拷贝构造函数
  1. 拷贝构造的三种情形
    1. 以一个对象直接构造另一个对象
    2. 函数参数
    3. 函数返回值
  2. 默认拷贝构造,逐成员初始化
  3. 位逐次拷贝语义(类似于memcpy)
    • 以下几种情况会抑制逐比特拷贝语义:
      1. 内含成员对象,且声明了拷贝构造函数(编译器合成或者显式定义)
      2. 派生自声明了(合成或者自定义)拷贝构造函数的基类
      3. 含有虚函数或者虚基类
  4. 拷贝构造函数合成时机:类不具有逐比特拷贝语义
/// 拷贝函数调用
Foo foo2 = foo1;
void Fun(Foo foo);
Foo Fun(){Foo foo; return foo;}

/// 默认拷贝构造
class String
{
    int len;
    char* str;
};

class Person
{
    int age;
    String name;
    String sex;
};

Person p1(10, "Li Hua", "男");
Person p2 = p1;     // p2.age = p1.age; p2.name.len = p2.name.len; p2.name.str = p2.name.str; p2.sex.len = p1.sex.len; p2.sex.str = p1.sex.str;
三、对象赋值语义
  1. 内含成员对象,且声明了operator=()(编译器合成或者显式定义)
  2. 派生自声明了(合成或者自定义)operator=()的基类
  3. 含有虚函数或者虚基类
四、程序转化语义,拷贝构造的调用策略

1、显示初始化

class X
{
    //...
};

X x0;

void Fun()
{
    X x1(x0);
    X x2 = x0;
    X x3 = X(x0);
}

void Fun()
{
    X x1;
    X x2;
    X x3;
    
    x1.X::X(x0);
    x2.X::X(x0);
    x3.X::X(x0);
}

2、参数初始化

// 一种策略
void Fun(X x0)
{
    //...
}

X xx;
Fun(xx);

// 转化
X _tmpx0;
_tmpx0.X::X(x0);
Fun(_tmpx0);

void Fun(X &x0);

3、返回值初始化

X Fun()
{
    X xx;
    //....
    return xx;
}

// 一种策略
// 猜测,可能返回类对象的函数可以直接复制和这个有关系,见下
void Fun(X &_result)
{
    X xx;
    xx.X::X();
    // 处理xx
    _result.X::X(xx);
    return;
}

X res;
Fun(res);

// 成员函数调用
Fun().some_memfun();
X _tmpx;
(Fun(_tmpx), _tmpx).some_memfun();
// 拷贝赋值函数调用
X x0;
(Fun(_tmpx), _tmpx).operator=(x0);

// 返回值优化
void Fun(X &_result)
{
    //X xx;
    //xx.X::X();
    // 处理xx
    _result.X::X();
    // 直接处理_result
    return;
}
默认构造函数示例
class TestA1
{
    private:
    	int		m_memInt;
    	char*	m_memStr;
}

class TestB1
{
    TestA1	m_memA;
}

class TestA2
{
    private:
    	int		m_memInt;
    	char*	m_memStr;
    public:
    	TestA1(){}
}

class TestB2
{
    TestA2	m_memA;
}

class TestA3
{
    private:
    	int		m_memInt;
    	char*	m_memStr;
    public:
    	TestA3(int nInt, char* szStr){}
}

class TestB3
{
    TestA3	m_memA;
}
拷贝构造函数示例
class TestA4
{
    private:
    	int		m_memInt;
    	char*	m_memStr;
}
class TestB4
{
    TestA4	m_memA;
}


class TestA5
{
    private:
    	int		m_memInt;
    	char*	m_memStr;
    public:
    	TestA5(const TestA5& rhs){}
}
class TestB5
{
    TestA5	m_memA;
    int		m_memInt;
}
class TestB5Ex
{
    TestA5	m_memA;
    int		m_memInt;
    public:
    	TestB5Ex(const TestB5Ex& rhs){}
}

class TestA6
{
    private:
    	int		m_memInt;
    	char*	m_memStr;
    public:
    	TestA6(){
            m_memInt = 0;
            m_memStr = nullptr;
            cout<<"无参构造"<<endl;
        }
    	TestA6(const TestA5& rhs){
            cout<<"拷贝构造"<<endl;
        }
}
class TestB6
{
    TestA6	m_memA;
    int		m_memInt;
}
class TestB6Ex
{
    TestA6	m_memA;
    int		m_memInt;
    public:
    	TestB6Ex(const TestB6Ex& rhs){}
}

int main(){
    TestB6 b6_1;
    TestB6 b6_2 = b6_1;
    
    TestB6Ex b6e_1;
    TestB6Ex b6e_2 = b6e_1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值