首页 > 其他分享 >学构造函数的这辈子有了

学构造函数的这辈子有了

时间:2024-09-02 19:25:51浏览次数:15  
标签:const 函数 成员 other 这辈子 拷贝 构造函数

拷贝构造函数

1.拷贝构造函数,是一个特殊的构造函数。系统默认提供了。但是可以手动定义。

2.功能:使用一个类对象给另一个类对象初始化时,会自动调用拷贝构造函数

3.定义格式

1、没有返回值
2、函数名与类同名
3、参数:该类的其他对象的引用
4、访问权限:一般为public
5、定义格式:类名 (类名 &other)

调用时机:

使用一个类对象给另一个初始化时:

string s1("hello world"); //调用有参构造

string s2 = s1; //调用拷贝构造

string s3(s1); //调用拷贝构造

使用值传递时实参取代形参时调用拷贝构造函数。

使用值返回时返回结果也是调用拷贝构造。

深浅拷贝问题:

如果类中有指针成员并且指向其它空间时,应调用深拷贝

使用浅拷贝就会出现多个对象中指针成员指向同一个内存空间,析构指针空间时,会造成对同一块内存空间的多次释放的情况,造成段错误(double free),此时就需要深拷贝。

深拷贝需要程序手动定义拷贝构造函数,在拷贝构造函数的初始化列表中,给新对象的指针成员重新分配空间,将原来对象指针空间指向的内容拷贝到该空间中即可完成深拷贝

Stu(Stu &other):name(other.name),age(other.age),score(other.score),ptr(new int(*other.ptr))
    {
        cout<<"Stu::深拷贝构造函数"<<endl;
    }

移动构造函数

如果类中不显性定义拷贝构造函数或者移动构造函数,那么系统会自动提供这两个函数,如果程序员手动定义了其中任意一个函数,系统就两个都不提供了,如果需要使用,则需要程序员自己手动定义

移动构造函数,是将临时空间或将亡空间,托管给一个新的对象。

1、没有返回值
2、函数名与类同名
3、参数:该类的其他对象的右值引用
4、访问权限:一般为public
5、定义格式:类名 (类名 &&other)
//自定义移动构造函数
    Stu(Stu &&other):name(other.name),age(other.age),score(other.score),ptr(new int(*other.ptr))
    {
        cout<<"Stu::移动构造函数"<<endl;
    }
     
    //调用移动构造函数
    Stu s3 = move(s1);

取地址运算符重载函数

功能:取得当前类对象的地址

定义格式

1、返回值:当前类的指针
2、参数:无
3、权限:一般为public
4、格式: 类名 * operator&()
    //自定义取地址运算符重载函数
    Stu * operator&()
    {
        cout<<"取地址运算符重载函数"<<endl;
        return this;
    }

    //取地址运算符重载函数
    &s1;

一个空类中默认提供的特殊成员函数

class Temp
{
    public:
        Temp(){}                   //无参构造
        Temp(const Temp &other){}     //拷贝构造
        ~Temp(){}                        //析构函数
        Temp * operator&(){return this;}     //取地址运算符重载函数
        Temp(const Temp &&other){}     //移动构造
        Temp &operator=(const Temp& other){}      //拷贝赋值函数
        Temp &operator=(const Temp&& other){}      //移动赋值函            
};

匿名对象

匿名对象就是没有名字的是对象,其生命周期就在调用的语句内,可以理解成一个将亡值。

定义时调用构造函数。

使用场景

1、使用匿名对象给一个新定义的对象进行初始化

2、使用匿名对象给数组进行初始化

3、使用匿名对象作为函数参数传递

    Stu("lisi", 20);             //定义一个匿名对象
    cout<<"***********************************"<<endl;

    //匿名对象使用方式1:给新的对象进行初始化工作
    Stu s2 = Stu("wangwu", 30);           //依赖移动构造

    cout<<"***********************************"<<endl;
    //匿名对象使用方式2:给对象数组进行初始化
    Stu s[3] = {Stu("zhaoliu", 30), Stu("sunqi", 30), Stu("zhouri", 30)};
    cout<<"***********************************"<<endl;

    //匿名对象使用方式3:作为函数的形参进行传递
    fun(Stu("wukong", 500));
    cout<<"***********************************"<<endl;

友元

可以在其他类中访问当前类的所有信息,友元可以无条件访问该类中的所有权限下的成员。

友元分为友元函数和友元类

class Stu;                  //对类的前置声明
void  fun(Stu s);  

//类中声明一个全局函数作为友元函数
friend void  fun(Stu s);

//定义一个全局函数
void  fun(Stu s)
{
    s.show();           //在类外可以正常调用类中的公共权限下的成员
    cout<<"name = "<<s.name<<endl;       //友元函数可以访问对应类中的所有权限下的成员
    cout<<"age = "<<s.age<<endl;        //友元函数可以访问对应类中的所有权限下的成员
}

 Stu s1("zhangsan", 18);
 fun(s1);//调用
#include <iostream>
using namespace std;
class Dog;
class Cat
{
private:
    int count;
    double weight;
public:
    Cat(){cout<<"无参构造"<<endl;}
    Cat (int c,double w):count(c),weight(w){cout<<"有参构造"<<endl;}
    ~Cat(){cout<<"析构函数"<<endl;}
    friend void sum(Cat &c,Dog &d);
};

class Dog
{
private:
    int count;
    double weight;
public:
    Dog(){cout<<"无参构造"<<endl;}
    Dog (int c,double w):count(c),weight(w){cout<<"有参构造"<<endl;}
    ~Dog(){cout<<"析构函数"<<endl;}
    friend void sum(Cat &c,Dog &d);
};

void sum(Cat &c,Dog &d)
{
    cout<<"猫总个数"<<c.count<<endl;
    cout<<"猫总重量"<<c.weight*c.count<<endl;
    cout<<"狗总个数"<<d.count<<endl;
    cout<<"狗总重量"<<d.weight*d.count<<endl;
}

int main ()
{
    Cat cat (5,1.50);
    Dog dog (6,2.00);
    sum (cat,dog);
    return 0;
}

友元类

声明一个A类为B类的友元类,则B允许A访问其所有权限下的成员包括私有成员

声明格式:friend 类名;

class teacher
{
    //定义成员函数
    void display(Stu s);          //只能类内声明,类外定义
}

  
//声明老师类为友元类
friend class Teacher;

友元的总结

1> 不到万不得已的情况下,不要使用友元,因为友元的出现使得封装称为虚谈,友元破坏了类的封装性

2> 友元不具有传递性:A是B的朋友,B不一定是A的朋友

3> 友元不具有传递性:A是B的朋友,B是C的朋友,A不一定是C的朋友

4> 友元不具有继承性:父类的朋友,不一定是子类的朋友

5> 必须使用友元的情况:插入和提取运算符重载时,只能使用友元函数来解决

常成员(const)

引入常成员可以保护成员函数和成员变量、常对象

成员函数仅仅对成员变量有只读权限,不需要进行更改,那么此时就需要对成员函数进行const,达到保护成员变量的功能。

在传递某个对象时,对方仅仅只是对该对象有只读权限,也需要使用常成员,进一步保护成员变量

常成员函数

1> 定义格式:定义成员函数时,在括号后加关键字 const

返回值类型 函数名(形参列表) const

2> 作用:在常成员函数中,是不允许更改成员变量的值

3> 类中常成员函数与同名的非 常成员函数构成重载关系,原因是,形参this的类型不同

非常成员函数中形参this:类名 * const this;

常成员函数中的形参this: 类名 const * const this;

4> 非 常对象,优先调用非常成员函数,如果没有该非常成员函数,那么就会调用同名的常成员函数

常对象

1> 定义格式:const 类名 对象名;

2> 常对象只能调用常成员函数,不能调用非常成员函数

mutable关键字

1> 使用该关键字修饰的成员变量,可以解除常属性,即使在常成员函数中也能更改该变量的值

  //定义成员函数
   void show()const        // 类名 const  * const this;

常函数

1> 格式:const 返回值类型 函数名(形参列表){函数体内容}

2> 功能:常函数是保护函数的返回值不被修改的

//引用函数,const修饰的函数称为常函数
const int &fun()
{
    static int num = 520;
    return num;
}

关于C/C++中const的使用

1> const修饰普通变量,表示定义的是一个常变量,该变量只可读不可写,定义时必须初始化

2> const修饰指针变量时,如果放在*前表示,指针所执行空间中的内容可读不可写

const int *p = &data; // p 指向的是 const int, 所以 *p 里的内容不能修改但是可以改变指向

如果放在*后,表示指针的值可读不可写,也就是指针指向不能改变

int *const p = &data; // p 是 const 指针, 所以 p 不能更换指向

如果两边都加,表示都不可以更改,都是可读不可写,包含指向和值

3> const修饰函数的形参,表示传过来的数据,可读不可写

4> const修饰函数返回值时,表示保护函数的返回结果不被修改(指针函数和引用函数)

5> const修饰常成员函数,放到成员函数最后面,表示保护成员变量不被修改

标签:const,函数,成员,other,这辈子,拷贝,构造函数
From: https://blog.csdn.net/sjrhsk_hahaha/article/details/141729824

相关文章

  • 18. 构造函数和析构函数,构造函数的分类和调用
    构造函数和析构函数构造函数//没有返回值不用写void//函数名与类名相同//可以有参数,可以发生重载//构造函数由编译器自动调用一次无须手动调用析构函数//没有返回值不用写void函数名与类名相同函数名前加~不可以有参数,不可以发生重载析构函数也是由编......
  • C++学习随笔——委托构造函数
    C++11中,引入了委托构造函数(delegatingconstructors)的概念。委托构造函数允许一个构造函数调用同一个类中的另一个构造函数,以减少代码重复。 委托构造函数的语法:classMyClass{public:MyClass(intx):value(x){//这个构造函数初始化value}M......
  • PHP8面向对象快速入门三 类的继承 类方法属性重写和final关键字 parent调用父类的方法
    在PHP中,类的继承(继承)是一种机制,允许一个类继承另一个类的属性和方法,从而实现代码的重用和扩展。继承可以帮助你创建一个基于现有类的新类,保留原有类的特性并增加或修改其功能。classAnimal{public$name='dongwu';protected$age=1;private......
  • C++ //练习 19.23 为你的Token类添加移动构造函数和移动赋值运算符。
    C++Primer(第5版)练习19.23练习19.23为你的Token类添加移动构造函数和移动赋值运算符。环境:LinuxUbuntu(云服务器)工具:vim 代码块classToken{ public: Token():tok(INT),ival(0){} Token(constToken&t):tok(t.tok){copyUnion(t);} Token&operator=(......
  • C++ 构造函数/析构函数中调用虚函数的情况简单测试
    #include<string>#include<iostream>usingnamespacestd;namespace{classAnimal{public:Animal(){cout<<"基类调用虚函数…"<<endl;cout<<GetInfo()<<e......
  • 【C++基础】类的构造函数和析构函数
    目录构造函数(Constructor)定义种类1.默认构造函数2.带参数的构造函数3.浅拷贝构造函数4.深拷贝构造函数深拷贝和浅拷贝的区别5.移动构造函数析构函数(Destructor)构造函数与析构函数的调用时机构造函数:析构函数:构造函数和析构函数的最佳实践避免在析构函数中抛出异......
  • PHP8面向对象快速入门二 构造函数 析构函数 静态变量 静态方法
    在PHP中,构造函数是一个特殊的方法,用于在创建对象时初始化对象的状态。构造函数在对象实例化时自动调用,以设置初始值或执行必要的准备工作。它可以接受参数,用于初始化对象的属性。构造函数的特点自动调用:构造函数在创建对象时自动调用。你不需要显式调用构造函数,它会在实例......
  • Secure Coding in C and C ++ (四)局部静态构造函数 虚函数
    前言上一章节我们讲解了关于C++静态和指针与引用的部分我们先来回顾一下相关的内容:指针说白了就是地址,inta;int*ptr=&a这里的整形指针就是存放的整数变量的地址静态static有两种层面:第一种层面就是在其他的文件里,如果加入了static修饰那么被修饰的在link......
  • 【C++学习笔记 18】C++中的隐式构造函数
    举个例子#include<iostream>#include<string>usingString=std::string;classEntity{private: Stringm_Name; intm_Age;public: Entity(constString&name) :m_Name(name),m_Age(-1){} Entity(intage) :m_Name("UnKnown")......
  • C/C++ 拷贝构造函数 | 赋值构造函数 | 移动构造函数 | 移动赋值构造函数
    文章目录前言1.拷贝构造函数(CopyConstructor)2.赋值构造函数(CopyAssignmentOperator)3.移动构造函数(MoveConstructor)4.移动赋值构造函数(MoveAssignmentOperator)总结前言C++中关于一个对象的构造,就有很多讲究。其中最常用的可能就是拷贝构造函数......