c++-进阶其他

转换构造函数

将其他类型转换为当前类型需要借助(转换)构造函数
转换构造函数也是一种构造函数,遵循一般构造函数的规则

#include <iostream>

using namespace std;

class Complex
{
private:
    double real;
    double imag;
public:
    Complex();
    Complex(double real,double imag);
    Complex(double real); // 转换构造函数 

    /*  
        友元函数
    */
    friend ostream& operator<<(ostream &out,Complex &c);
};

Complex::Complex()
{
    this->real=0.0;
    this->imag=0.0;
}

Complex::Complex(double real,double imag)
{
    this->imag=real;
    this->real=imag;
}

/*
    转换构造函数
    将double类型的参数real转换为complex类的对象

    转换构造函数也是构造函数,也可以用来进行初始化
*/
Complex::Complex(double real)
{
    this->real=real;
    this->imag=0.0;
}

// 将外部函数定义为友元函数
ostream & operator<<(ostream &out,Complex &c)
{
    cout<<"重载<<"<<endl;
    out<<c.real<<"+"<<c.imag<<"i"<<endl;
    return out;
}

int main()
{
    Complex a(10.0,20.2);
    cout<<a<<endl;

    /*
        等价于 a.complex(25.5)
        将赋值的过程转换成了函数调用的过程
    */
    a=25.5; // 调用转换构造函数
    cout<<a<<endl;
    
    /*
        以拷贝的方式初始化对象
        在以拷贝的方式初始化对象时,编译器先调用转换构造函数,将25.2转换为Complex类型,在拷贝给c

        对于已经重载了+运算符,可以进行算数相加
        c2=c1+20.2;
    */
    Complex c=20.2;

    return 0;
}

将当前类型转换为其他类型(类型转换函数)

operator datatype(){return data} type是要转换的目标类型,data是要返回的datatype类型的数据
只能出现在类中,类中的成员函数,该函数可以没有返回值类型的定义

#include <iostream>

using namespace std;

class Complex
{
private:
    double real;
    double imag;
public:
    Complex();
    Complex(double real,double imag);
    Complex(double real); // 转换构造函数 

    /*  
        友元函数
    */
    friend ostream& operator<<(ostream &out,Complex &c);

    friend Complex operator+(const Complex &c1,const Complex &c2);

    /*
        类型转换函数
    */
   operator double() const;

};

Complex::Complex()
{
    this->real=0.0;
    this->imag=0.0;
}

Complex::Complex(double real,double imag)
{
    this->real=real;
    this->imag=imag;
}

/*
    转换构造函数
    将double类型的参数real转换为complex类的对象

    转换构造函数也是构造函数,也可以用来进行初始化
*/
Complex::Complex(double real)
{
    this->real=real;
    this->imag=0.0;
}

// 将外部函数定义为友元函数
ostream & operator<<(ostream &out,Complex &c)
{
    cout<<"重载<<"<<endl;
    out<<c.real<<"+"<<c.imag<<"i"<<endl;
    return out;
}

Complex operator+(const Complex &c1,const Complex &c2)
{
    Complex c;
    c.real=c1.real+c2.real;
    c.imag=c1.imag+c2.imag;

    return c;
}

/*
    类型转换函数
*/
Complex::operator double() const
{
    return this->real;
}

int main()
{
    Complex c1(10.,20.);
    double f1=c1; // double d1 =Complex::operator double(&c1)
    cout<<f1<<endl;


    int n=Complex(11.,12.);
    cout<<n<<endl;

    return 0;
}

类型转换进阶 – 没看

见文档P392

移动构造函数

https://blog.csdn.net/weixin_44788542/article/details/126284429
https://blog.csdn.net/yue152152/article/details/127214251

C++11中的方法

拷贝构造与移动构造

拷贝构造

临时对象和拷贝构造后的对象各自占用不同的且大小相同的内存空间
即临时对象和新创建的对象申请的内存同时存在

对于匿名对象
只能调用const引用 这是因为常量左值一弄可以接受左值、右值、常量左值、常量右值
非常量左值引用,只能接收左值

对于非匿名对象(非临时对象,拷贝构造时可以选择const& 也可以选择非const&
系统优先选择后者(非const引用))
在这里插入图片描述

例子

g++ file.cpp -o file -fno-elide-constructors 取消编译优化

#include <iostream>
#include <string>

using namespace std;

class Integer
{
private:
    int *m_ptr;
public:
    Integer(int value);
    Integer(const Integer &src);
    Integer(Integer &src);
    ~Integer();
   
   int getValue(void);
};

Integer::Integer(int value)
    : m_ptr(new int(value))
{
    cout<<"有参构造函数"<<endl;
}

// 参数为常量左值引用的深拷贝构造函数
Integer::Integer(const Integer &src)
    : m_ptr(new int(*src.m_ptr)) // 创建的同时初始化
{
    cout<<"有参深拷贝构造函数"<<endl;
}

// 参数为左值引用的浅拷贝构造函数,转移堆内存资源所有权
Integer::Integer(Integer &src)
    : m_ptr(src.m_ptr) // 共享内存空间
{
    src.m_ptr=NULL; // 释放空间
    cout<<"有参浅拷贝构造函数"<<endl;
}

Integer::~Integer()
{
    cout<<"析构函数"<<endl;
    delete m_ptr;
}

int Integer::getValue(void)
{
    return *m_ptr;
}

Integer getNum(void)
{
    Integer a(100); // 有参构造函数
    return a;
}

int main()
{
    // 对于匿名对象
    // 只能调用const引用 这是因为常量左值一弄可以接受左值、右值、常量左值、常量右值
    // 非常量左值引用,只能接收左值
    Integer a(getNum()); // 拷贝构造
    cout<<"a: "<<a.getValue()<<endl;

    cout<<"*********"<<endl;
    // 对于非匿名对象(非临时对象,拷贝构造时可以选择const& 也可以选择非const&
    //               系统优先选择后者(非const引用))
    Integer temp(1000);
    Integer b(temp); //
    cout<<"b: "<<b.getValue()<<endl;

    return 0;
}
/*
    有参构造函数
    有参浅拷贝构造函数 // 局部变量到临时变量
    析构函数
    有参深拷贝构造函数 // 临时变量到主函数变量
    析构函数
    a: 100
    *********
    有参构造函数
    有参浅拷贝构造函数
    b: 1000
    析构函数
    析构函数
    析构函数
*/

移动构造

让这个临时对象原本控制的内存空间转移给构造出来的对象
原本由临时对象申请的内存空间,由于新创建对象的接管,临时对象不再指向该堆内存

返回返回一个局部变量,此时就是一个临时变量,因为在函数结束后就消亡了,对应内部的动态内存也会被析构掉,所以系统在执行return函数之前,需要在生成一个临时对象将a中的数据内存返回到被调的主函数中,

  1. 可以调用拷贝构造函数进行备份
  2. 使用移动构造函数把即将消亡的且仍需要用到的这部分内存的所有权进行转义,手动延长它的声明周期
  3. 如果没有移动构造函数,就使用普通的拷贝构造函数,否则优先选择移动构造函数
    在这里插入图片描述

例子

g++ file.cpp -o file -fno-elide-constructors 取消编译优化

#include <iostream>
#include <string>

using namespace std;

class Integer
{
private:
    int *m_ptr;
public:
    Integer() {m_ptr=new int(10);};
    Integer(int value);
    Integer(const Integer &src);
    Integer(Integer &&src);
    ~Integer();
   
   int getValue(void);
};

Integer::Integer(int value)
    : m_ptr(new int(value))
{
    cout<<"有参构造函数"<<endl;
}

// 参数为常量左值引用的深拷贝构造函数
Integer::Integer(const Integer &src)
    : m_ptr(new int(*src.m_ptr)) // 创建的同时初始化
{
    cout<<"有参深拷贝构造函数"<<endl;
}

// 参数为左值引用的浅拷贝构造函数,转移堆内存资源所有权
Integer::Integer(Integer&& src)
    : m_ptr(src.m_ptr) // 共享内存空间
{
    src.m_ptr=NULL; // 释放空间
    cout<<"有参移动构造函数"<<endl;
}

Integer::~Integer()
{
    cout<<"析构函数"<<endl;
    delete m_ptr;
}

int Integer::getValue(void)
{
    return *m_ptr;
}

Integer getNum(void)
{
    Integer a(100); // 无参构造函数
    return a;
}

int main()
{
	/*
		返回返回一个局部变量,此时就是一个临时变量,因为在函数结束后就消亡了,对应内部的动态内存也会被析构掉,所以系统在执行return函数之前,需要在生成一个临时对象将a中的数据内存返回到被调的主函数中,
		1. 可以调用拷贝构造函数进行备份
		2. 使用移动构造函数把即将消亡的且仍需要用到的这部分内存的所有权进行转义,手动延长它的声明周期
		3. 如果没有移动构造函数,就使用普通的拷贝构造函数,否则优先选择移动构造函数
	*/
    Integer a(getNum()); // 拷贝构造
    cout<<"a: "<<a.getValue()<<endl;

    cout<<"*********"<<endl;
    // 对于非匿名对象(非临时对象,拷贝构造时可以选择const& 也可以选择非const&
    //               系统优先选择后者(非const引用))
    Integer temp(1000);
    Integer b(temp); //
    cout<<"b: "<<b.getValue()<<endl;

    return 0;
}
/*
    有参构造函数 
    有参移动构造函数 // 局部变量到临时变量 不能调用const引用
    析构函数
    有参移动构造函数 // 临时变量到主函数变量 
    析构函数
    a: 100
    *********
    有参构造函数
    有参深拷贝构造函数
    b: 1000
    析构函数
    析构函数
    析构函数
*/

例子2

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

class MyClass
{
private:
    char *str;
public:
    MyClass(); // 默认构造函数
    MyClass(const char *s); // 构造函数重载 深拷贝
    ~MyClass();

    MyClass & operator=(const MyClass &s); // 拷贝赋值操作符重载 (没有重载操作符时,或自动生成一个默认的)

    MyClass(MyClass &&s); // 移动构造,右值引用

    MyClass & operator=(MyClass &&s); // 移动赋值运算符重载
};

MyClass::MyClass(/* args */) // 构造函数
    :str(new char[1])
{
    cout<<"默认构造函数"<<endl;
    str[0]=0;
}

MyClass::MyClass(const char *s) // 构造函数重载
{
    cout<<"const 深拷贝"<<endl;
    str=new char[strlen(s)+1];
    strcpy(str,s);
}

MyClass & MyClass::operator=(const MyClass &s)
{
    cout<<"operator="<<endl;

    if (this->str!=s.str)
    {
        delete this->str;
        this->str=new char[strlen(s.str)+1];
        strcpy(this->str,s.str);
    }

    return *this;
}

MyClass::MyClass(MyClass &&s)
    :str(s.str)
{
    cout<<"移动构造"<<endl;
    s.str=new char[1];
    s.str[0]=0;
}

MyClass & MyClass::operator=(MyClass &&s)
{
    cout<<"移动operator="<<endl;
    if (this->str!=s.str)
    {
        this->str=s.str;
        s.str=new char[1];
        s.str[0]=0;
    }

    return *this;
}

MyClass::~MyClass()
{
    cout<<"析构函数"<<endl;
}

template <class T>
void moveSwap(T &a,T &b)
{
    T tmp(move(a)); // std::move() 为右值,这里会调用移动构造函数
    a=move(b); // move(b) 为右值 因此这里会调用移动构造函数
    b=move(tmp); // 同上
}


int main()
{
    MyClass s; // 默认构造

    cout<<"*********"<<endl;
    MyClass s1(MyClass("this1")); // 移动构造

    cout<<"*********"<<endl;
    MyClass s2;
    s2=MyClass("this2"); // 移动构造operator=


    return 0;
}

/*
    默认构造函数
    *********
    const 深拷贝
    移动构造
    析构函数
    *********
    默认构造函数
    const 深拷贝
    移动operator=
    析构函数
    
    析构函数
    析构函数
    析构函数
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值