精华内容
下载资源
问答
  • 我就斗胆将他们命名为六大函数好了。 一、构造函数 c++primer中说过:构造函数是特殊的成员函数,只要创建类类型的新对象,都要执行构造函数。构造函数的工作就是保证每个对象的数据成员具有合适的初始值。 构造...

    在C++中,有三大函数复制控制(复制构造函数,赋值操作符,析构函数),而在C++11中,加入了移动构造函数,移动赋值操作符。我就斗胆将他们命名为六大函数好了。

    一、构造函数

    c++primer中说过:构造函数是特殊的成员函数,只要创建类类型的新对象,都要执行构造函数。构造函数的工作就是保证每个对象的数据成员具有合适的初始值。

    构造函数与其他函数不同:构造函数和类同名,没有返回类型。

    构造函数与其他函数相同:构造函数也有形参表(可为void)和函数体。  (参数表为void的构造函数为默认构造函数)

    构造函数构造类对象的顺序是:1.内存分配,构造函数调用的时候 隐士\显示的初始化各数据。

    2.执行构造函数的运行。

    1、构造函数初始化表

    A() :a(0){}
    我们使用构造函数初始化表示初始化数据成员,然而在没有使用初始化表的构造函数则在构造函数体中对数据成员赋值。

    在我们编写类的时候,有些成员必须在构造函数初始化表中进行初始化。(没有默认构造函数的类类型成员,const或者引用类型成员)

    在编写代码的时候,要注意的是:可以初始化const对象或者引用类型的对象,但不能对他们进行赋值。 也就是需要在我们执行构造函数函数体之前完成初始化工作,所以唯一的机会就是初始化表。从这一点可以看出初始化表的执行先于函数体。

    在初始化表中,成员被初始化的次序不是你编写初始化表的次序,而是定义成员的次序。


    初始化列表在初始化类类型的成员时,要指定实参并传递给成员类型的一个构造函数。

    在c++primer中有一个书店的例子:

    Sales-item(): isbn(10, '9'), units_sold(0), revenue(0.0) {}


    我们的初始化表在什么时候必须使用呢 ?

    当有一个类成员,他本身就是结构或者类的时候,并且只有一个带参数的构造函数,(无默认构造函数) 此时我们要对成员进行初始化,就需要调用成员的构造函数,此时需要我们的初始化表,如果不使用初始化表,那么内存分配就会出问题。

    初始化列表的优点:主要是对于自定义类型,初始化列表是作用在函数体之前,他调用构造函数对对象进行初始化。

    然而在函数体内,需要先调用构造函数,然后进行赋值,这样效率就不如初始化表。



    2、默认实参构造函数

    A(int i = 1) :a(i), ca(i), ra(i){}


    3、默认构造函数

    合成的默认构造函数:当类中没有定义构造函数(注意是构造函数)的时候,编译器自动生成的函数。

    但是我们不能过分依赖编译器,如果我们的类中有复合类型或者自定义类型成员,我们需要自己定义构造函数。

    自定义的默认构造函数:

    A(): a(0) {}
    A(int i = 1): a(i) {}
    可能疑问的是第二个构造函数也是默认构造函数么?是的,因为参数中带有默认值。

    我们来看一张图,就会一目了然了:


    4、类型转换

    在C++primer中,书店问题中的一个例子是 传递string对象或者iostream对象到参数中,会发生隐式转换,这样就会出现问题。

    explicit关键字可以抑制隐式转换。

    explicit Sales_item(const string &book): isbn(book) {}

    如果我们声明了构造函数禁止隐式转换, 可以将其他对象显示转换后传入构造函数。

    string a = "d";
    item.same(Sales_item(a));

    二、移动构造函数

    在C++11中新加入的特性!

    在上一篇blog中我加入了一张图,可以具体看到移动构造函数的运行原理。


    此时,我们偷走了临时变量的内存空间,据为己用。节省了开辟空间的时间。

    	A(A && h) : a(h.a)
    	{
    		h.a = nullptr; //还记得nullptr?
    	}

    可以看到,这个构造函数的参数不同,有两个&操作符,   移动构造函数接收的是“右值引用”的参数。

    还要来说一下,这里h.a置为空,如果不这样做,h.a在移动构造函数结束时候执行析构函数会将我们偷来的内存析构掉。h.a会变成悬垂指针

    移动构造函数何时触发?  那就是临时对象(右值)。用到临时对象的时候就会执行移动语义。

    这里要注意的是,异常发生的情况,要尽量保证移动构造函数 不发生异常,可以通过noexcept关键字,这里可以保证移动构造函数中抛出来的异常会直接调用terminate终止程序。

    右值引用:

    在上一篇blog中,我们提到过将亡值,他是c++11新增的跟右值引用相关的表达式。

    在c++11中,右值引用就是对一个右值进行引用的类型,右值通常不具有名字,我们就只能通过引用的方式找到它的存在了。

    比较一下下面两条语句:

    T &&a = returna();
    T b = returnb();
    此时a是右值引用,他比b少了一次对象析构和对象构造的过程。a直接绑定了returna返回的临时变量。b只是由临时变量值构造而成的。

    应该可以看清楚了吧。右值引用就是让返回的右值(临时对象)重获新生,延长生命周期。临时对象析构了,但是右值引用存活。

    不过要注意的是,右值引用不能绑定左值:int a; int &&c = a;   这样是不行的。


    这里有一个函数就是 move函数,它能够将左值强制转换成右值引用。


    三、移动赋值操作符

    他的原理跟移动构造函数相同,这里不再多说。

    给出实现代码:

    	A & operator = (A&& h)
    	{
    		assert(this != &h);
    
    		a = nullptr;
    		a = move(h.a);
    		h.a = nullptr;
    		return *this;
    	}



    复制控制

    四、复制构造函数

    他是一种特殊的构造函数,具有单个形参,形参是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数。当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式使用复制构造函数。

    必须定义复制构造函数的情况:

    1.、类有一个或者多个数据成员是指针。

    2、有成员表示在构造函数中分配的其他资源。另外的类在创建新对象时必须做一些特定的工作。

    下面给出赋值构造函数的编写:

    A(const A& h) :a(h.a){}
    如果不想让对象复制呢? 那就将复制构造函数声明为:private;

    五、赋值操作符

    他跟构造函数一样,赋值操作符可以通过制定不同类型的右操作数而重载。

    赋值和复制经常是一起使用的,这个要注意。

    下面给出赋值操作符的写法:

    	A& operator = (const A& h)
    	{
    		assert(this != &h);
    
    		this->a = h.a;
    
    		return *this;
    	}


    六、析构函数

    是构造函数的互补,当对象超出作用域或动态分配的对象被删除时,将自动应用析构函数。析构函数可用于释放对象时构造或在对象的生命期中所获取的资源。不管类是否定义了自己的析构函数,编译器都会自动执行类中非static数据成员的析构函数。

    析构函数的运行:

    当对象引用或指针越界的时候不会执行析构函数,只有在删除指向动态分配对象的指针或实际对象超出作用域时才会调用析构函数。

    合成析构函数:

    编译器总是会合成一个析构函数,合成析构函数按对象创建时的逆序撤销每个非static成员。要注意的是,合成的析构函数不会删除指针成员所指向的对象。


    最后要注意的是:类如果需要析构函数,那么他肯定也需要复制构造函数和赋值操作符。



    blog的最后给出完整的六大函数的代码。

    #include <iostream>
    #include <assert.h>
    using namespace std;
    
    class Temp
    {
    public:
    	Temp(const char* str = nullptr);
    	Temp(Temp&& t);
    	Temp& operator = (Temp&& t);
    	Temp(const Temp& t);
    	Temp& operator = (Temp& t);
    	~Temp(void);
    private:
    	char *m_pData;
    };
    
    Temp::Temp(const char* str)
    {
    	if (!str)
    	{
    		m_pData = nullptr;
    	}
    	else
    	{
    		this->m_pData = new char[strlen(str) + 1];
    		strcpy(this->m_pData, str);
    	}
    }
    
    Temp::Temp(Temp&& t) :m_pData(move(t.m_pData))
    {
    	t.m_pData = nullptr;
    }
    
    Temp& Temp::operator = (Temp&& t)
    {
    	assert(this != &t);
    
    	this->m_pData = nullptr;
    	this->m_pData = move(t.m_pData);
    	t.m_pData = nullptr;
    
    	return *this;
    
    }
    
    Temp::Temp(const Temp& t)
    {
    	if (!t.m_pData)
    	{
    		this->m_pData = nullptr;
    	}
    	else
    	{
    		this->m_pData = new char[strlen(t.m_pData) + 1];
    		strcpy(this->m_pData, t.m_pData);
    	}
    }
    
    Temp& Temp::operator = (Temp &t)
    {
    	if (this != &t)
    	{
    		delete[] this->m_pData;
    		if (!t.m_pData)
    		{
    			this->m_pData = nullptr;
    		}
    		else
    		{
    			this->m_pData = new char[strlen(t.m_pData) + 1];
    			strcpy(this->m_pData, t.m_pData);
    		}
    	}
    
    	return *this;
    }
    
    Temp::~Temp(void)
    {
    	if (this->m_pData)
    	{
    		delete[] this->m_pData;
    		this->m_pData = nullptr;
    	}
    }



    ---2013.12.20

    展开全文
  • 类中默认的个成员函数 构造函数 析构函数 拷贝构造函数 赋值操作符重载 取地址和const取地址操作符重载 const成员函数 1. 类中默认的个成员函数 首先看看下面代码 class A{ }; int main(){ A a; return 0; } ...
    • 类中默认的六个成员函数
    • 构造函数
    • 析构函数
    • 拷贝构造函数
    • 赋值操作符重载
    • 取地址和const取地址操作符重载
    • const成员函数

    1. 类中默认的六个成员函数
    首先看看下面代码

    class A{
    };
    int main(){
    	A a;
    	return 0;
    }
    

    这个代码并没有报错,也能正常的运行,那为什么我们都没有写构造函数也能对我们的类实例化。这是因为在类中含有默认的六个成员函数,包括了构造函数,析构函数,拷贝构造函数,赋值操作符重载,取地址和const去地址操作符的重载。
    在这里插入图片描述
    六个默认的成员函数都有自己的功能

    • 构造函数和析构函数:主要完成初始化和清理的工作
    • 拷贝赋值:拷贝构造是使用同类对象初始化创建对象,赋值重载主要是把一个对象赋值给另一个对象
    • 取地址重载:主要是普通对象和const对象取地址。

    2. 构造函数
    构造函数就是完成的我们的初始化的工作,在我们每次创建一个对象的时候都会调用构造函数并且在对象的声明周期值调用一次,构造函数格式。注意我们的构造函数时没有返回值的。

    类名(参数列表){
    	函数体;
    };
    
    • 无参构造
      顾名思义就是在构造函数中参数列表是没有构造函数的,比如下面的类
    #include <string>
    class Car{
    public:
    	Car(){
    		
    	}
    private:
    	std::string color;
    	int price;
    };
    int main(){
    	Car car;
    	return 0;
    }
    
    • 有参构造,就是在构造函数参数列表中含有参数。
    #include <string>
    class Car{
    public:
    	Car(std::string color,int price){
    		
    	}
    private:
    	std::string _color;
    	int _price;
    };
    int main(){
    	Car car("yellow",100000);
    	return 0;
    }
    

    注意:

    • 如果类中没有显示定义构造函数,c++编译器会自动生成一个无参的默认构造函数,一旦用户自己实现了构造函数便不再生成。
    • 无参的构造函数和全缺省的构造函数都称为默认的构造函数,并且默认的构造函数只能有一个,(无参构造函数,全缺省构造函数,编译器生成的构造函数都认为是默认成员函数)
    • 对自定义类型我们的构造函数中不会做任何的事情,但是对于自定义类型会调用自定义类型的构造函数,看下面的代码
    #include <string>
    class Car{
    public:
    	Car(std::string color,int price){
    		
    	}
    private:
    	std::string _color;
    	int _price;
    };
    int main(){
    	Car car("yellow",100000);
    	return 0;
    }
    

    会出现下面结果,这就说明了我们调用了自定义类型的构造函数。在这里插入图片描述

    3. 析构函数
    析构函数和我们的构造函数时对应的,他两就标志了一个对象从出生到灭亡,析构函数就是完成对象的销毁的,完成类中的资源的清理。
    格式:

    ~类名(){
    };
    

    析构函数特点:

    • 析构函数名是在类名前加上~
    • 无参数无返回值
    • 一个类有且只有一个析构函数,若没有显示定义会自动生成
    • 对象生命周期结束的时候自动调用

    注意:

    在析构函数中也会分为我们的自定义类型和内置类型,当我们的内置类型的时候析构函数不会做任何事情,但是对于自定义类型会调用自定义类型的析构函数,比如下面的代码

    #include <iostream>
    #include <string>
    class Pro{
    public:
    	Pro(){
    		std::cout << "Pro()" << std::endl;
    	}
    	~Pro(){
    		std::cout << "~Pro" << std::endl;
    	}
    private:
    	std::string name;
    	std::string address;
    };
    class Car{
    public:
    	Car(std::string color,int price){
    		
    	}
    private:
    	std::string _color;
    	int _price;
    	Pro p;
    };
    void test(){
    	Car car("yellow", 100000);
    }
    int main(){
    	test();
    	system("pause");
    	return 0;
    }
    

    在这里插入图片描述

    • 对于在堆上申请的空间或者文件描述符,或者套接字等等在析构函数中一定要进行回收或者关闭,这些资源是有限的,不手动释放就会一直存在下去,知道我们的程序运行结束。

    4. 拷贝构造函数
    拷贝构造函数也是构造函数,他与无参构造和有参构造不同的是他是用一个对象去初始化另一个对象,一般只有一个形参,就是本类类型对象的引用
    格式:

    类名(const 类& 对象)
    {
    }
    
    • 这里一定要加上我们的引用对象,当我们不加引用对象的时候在vs下就直接报错了,
      在这里插入图片描述
      原理是我们调用拷贝构造的时候不加上&的时候,我们是调用函数,形参数实参的一份拷贝,此时在拷贝形参的时候又会出现拷贝构造,这样就一直循环,程序崩溃,所以在vs上就直接报错了。引发无穷递归。
      默认的拷贝构造函数时字节序值拷贝(也称为浅拷贝)

    • 在我们没有声明拷贝构造函数的时候编译器会自动生成一个默认的拷贝构造函数,但是此时的拷贝构造函数并不适用所以的情况,当我们这里出现了在堆上申请空间的时候,比如下面的代码,看看有没有什么问题

    #include <iostream>
    #include <string>
    class Pro{
    public:
    	Pro(){
    		std::cout << "Pro()" << std::endl;
    		name = (char*)malloc(1024);
    	}
    	~Pro(){
    		std::cout << "~Pro" << std::endl;
    		free(name);
    	}
    private:
    	char* name;
    	std::string address;
    };
    

    上面的代码在看起来应该是没有毛病的,但是在我们进行拷贝构造的时候呢,只是单纯的值拷贝,
    在这里插入图片描述
    此时的时候应该是出错的,因为我们在申请a之后又拷贝构造将a的值拷贝给b,所以在a和b中的char* name是指向的同一块内存,当我们调用析构函数的是会出现这块内存被释放了两次。这时候应该使用深拷贝,后面我们再对深拷贝进行详细的讲解。

    5. 赋值运算符重载
    赋值运算符重载就是为了代码的可读性,比如我们两个类进行赋值的时候如果不写赋值运算符重载的话就要用一个函数来实现我们的赋值,函数在调用的时候可读性没有我们的“=”高,所以c++实现了运算符的重载,在我们不实现的时候就默认生成了。运算符重载在我们的日期类的实现的时候都了解过了,这里我们再总结一下
    函数原型:返回值类型 operator操作符 (参数列表)

    • 不能通过连接其他符号来创建新的操作符,比如@#¥等等
    • 重载操作符必须有一个类类型或者枚举类型的操作数
    • 用于内置类型的操作符,器含义不能改变:比如内置的整形+。
    • 作为类成员的重载函数时,器形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参
    • .* :: sizeof ?: **.**是不能运算符重载的。

    实现赋值运算符重载

    #include <iostream>
    #include <vector>
    class car{
    
    	car& operator=(const car& c){
    		if (&c == this){
    			return *this;
    		}
    		this->name = c.name;
    		this->price = c.price;
    		return *this;
    	}
    private:
    	std::string name;
    	int price;
    };
    

    赋值运算符的注意点:

    • 参数类型是引用和const,因为在传递的时候是不能去修改参数的
    • 返回值的检查(在内置类型是可以连续赋值的a=b=c),不能去改变我们原有的功能
    • 检测是否自己给自己赋值
    • 返回*this
    • 一个类如果没有显示定义赋值运算符重载,编译器会生成一个,完成按照字节序进行拷贝。

    6. 取地址以及const取地址操作符重载、
    取地址以及const取地址操作符重载是就是取出我们this指针,就是指向我们当前对象的地址,一般来说我们不去自己生成一个取地址操作符重载,只有在特殊的情况下才会去重载我们的const,比如我们不想让别人取的我们的地址我们可以重写,如下

    #include <iostream>
    #include <vector>
    class car{
    public:
    	car& operator=(car c){
    		if (&c == this){
    			return *this;
    		}
    		this->name = c.name;
    		this->price = c.price;
    		return *this;
    	}
    	car* operator&(){
    		return nullptr;
    	}
    private:
    	std::string name;
    	int price;
    };
    int main(){
    	car a;
    	std::cout << &a << std::endl;
    	system("pause");
    	return 0;
    }
    

    就永远取地址都得到的是NULL;

    7. const修饰成员函数
    将const修饰的类成员函数称之为const成员函数,实际上修饰的是this指针,表明该成员函数中不能对类的任何成员进行修改
    在这里插入图片描述
    此时发现我们队this指向name进行修改的时候直接报错,所以const修饰的成员函数不能去修改this指针指向的内容

    展开全文
  • 我们知道大神们在设计C++时候就给C++有个默认的函数,所谓默认就是,无需我们这些程序员们动手去写,只要你在将类实例化,即创建一个对象,在利用对象进行数据操作时候,就会编译器自动调用默认的函数,但是默认...

           我们知道大神们在设计C++时候就给C++有六个默认的函数,所谓默认就是,无需我们这些程序员们动手去写,只要你在将类实例化,即创建一个对象,在利用对象进行数据操作时候,就会编译器自动调用默认的函数,但是默认函数并不是C++希望我们使用的,真正强大的是我们在这些默认的基础之上,自己 DIY函数来实现默认函数所不能做到的和它能做到,只有这样才能将自己的功力大增。下面是我在编写C++ 函数时候产生的一些思考:

       六个默认的函数依次是:

    //C++ 的六个默认函数
    //在使用的时候那些函数时透明的,就是那些函数学了一招隐身技术 啊哈哈哈啊 
    class Default
    {
    public:
    /* 
    Default(){}//缺省构造函数
    Default(const Default&){}//拷贝构造函数 
    ~Default(){}//析构函数 
    Default& operator=(const Default&){}//赋值运算符 
    Default* operator&(){}//取址运算符 
    const Default* operator&()const{}//取址运算符 
    const
    */
    private:
    	int m_Data; 
    };
    int main()
    { 
    	Default t;//调用构造函数
    	Default t1=t;//Default t1(t);
    	//调用拷贝构造函数 
    	Default t2;t2=t; //调用赋值函数
    	Default *pt = &t;//调用取址函数
    	const Default t3;
    	const Default *pt1 = &t3;//调用const取址函数 
    	//调用析构函数
    	return 0;
    } 

     
    

    C++的强大之处不在于有多少默认缺省的封装的方法,而是,在与在满足这些基本函数的基础上给予编程者最大的创造空间。这些默认的函数只能保证C++的正常模式,在此基础之上有极大的接口空间来设计与实现方法

    1.我们看一个程序

    /**********************************************************************    
    * *   Copyright (c)2015,WK Studios  
    * *   Filename:  A.h
    * *   Compiler: GCC  vc 6.0   
    * *   Author:WK    
    * *   Time: 2015 4 5  
    * **********************************************************************/
    #include<iostream>
    
    using std::cout;
    using std::cin;
    
    
    
    class S
    {
    public:
    	//当使用自定义构造函数的时候编译器就不会调用默认的构造函数
    
    	 S(int i=0,double n=0):m_data(i),data(n)
    	{
    	cout<< this<<"\n";
    	}
    private:	
    	
    	int m_data;
            double data;
    
    };
    int main()
    {
    S s0; //1  //此时就是我们自定义了构造函数编译器就不会再调用默认的无参构造函数,
              //如果想要这么做,必须自定义一个无参构造函数,或者自定义缺省的构造函数,
             //就像上面函数的那样,也就是说如果么有缺省值,就会报错,因为找不到对应的构造函数
    S(10);//2
    S(10.8); //3
    S((int)10.8);//4
    
    S ss(10,20);//5
    S ss1(10.8);//6
    S ss2((int)10.8);//7
    
    S s(10,10.8);//8  //调用了构造函数
    S s1 = (S)(10,10.8);//9
    }


    下来我们验证一下:

    /**********************************************************************    
    * *   Copyright (c)2015,WK Studios  
    * *   Filename:  A.h
    * *   Compiler: GCC  vc 6.0   
    * *   Author:WK    
    * *   Time: 2015 4 5  
    * **********************************************************************/
    #include<iostream>
    
    using std::cout;
    using std::cin;
    
    
    
    class S
    {
    public:
    	//当使用自定义构造函数的时候编译器就不会调用默认的构造函数
       //explicit   只对构造函数起作用,用来抑制隐式转换。
    	 S(int i=0,double n=0.0):m_data(i),data(n)
    	{
    		 cout<<"Create S obj:"<< this<<"\n";
    	}
    
    	S(const S &t)
    	{
    		cout<<"Copy Test Obj : "<<this<<"\n";
    		m_data = t.m_data;
    	}
    	S& operator=(const S &t)
    	{
    		cout<<"Assgin:"<<this<<" : "<<&t<<"\n";
    		if(this != &t)
    		{
    			m_data = t.m_data;
    		}
    		return *this;
    	}
    		~S()
    	{
    		cout<<"Free S Obj :"<<this<<"\n";
    	}
    
    
    private:	
    	
    	int m_data;
        double data;
    
    };
    int main()
    {
    S(10);//1
    
    S ss(10,20);//2
    S ss1(10.8);//3
    S ss2((int)10.8);//4
    
    S s(10,10.8);//5
     S s1 = (10,10.8);//6
    S s2;    //7
    s2=(10,10.8);
    
    }






    展开全文
  • C++类中的六大默认成员函数

    千次阅读 多人点赞 2021-04-10 23:04:09
    构造函数 构造函数并不是去构造函数函数,而是去对函数进行初始化的函数。构造函数函数名与类名相同,当我们每次创建类对象的时候,就会自动调用构造函数。构造函数在对象的生命周期中只会调用1次。 class Date...

    在C++中,当你去创建一个类的时候,即便这个类是空类,也会自动生成下面6个默认成员函数,在本篇博客中,我将逐一分析下面6个默认成员函数。

                                

    构造函数

    构造函数并不是去构造函数的函数,而是去对函数进行初始化的函数。构造函数的函数名与类名相同,当我们每次创建类对象的时候,就会自动调用构造函数。构造函数在对象的生命周期中只会调用1次。

    class Date
    {
    public:
        //构造函数
    	Date(int year = 2021, int month = 4, int day = 11)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };

    构造函数的几个特点

       ①函数名与类名相同

       ②无返回值

       ③对象实例化时编译器自动调用对应的构造函数

       ④构造函数可以重载

    class Date
    {
    public:
        //构造函数的重载:
        //无参的构造函数
    	Date()
    	{}
        //需要传参的构造函数
    	Date(int year, int month, int day)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };

       ⑤如果类中没有显式定义构造函数(就是自己没有去定义构造函数),那么编译器会自动生成一个无参的默认构造函数;

          如果类中显式定义了构造函数,那么编译器将不再生成,而是去使用用户定义的构造函数。

       ⑥默认构造函数只能同时存在1个。默认构造函数分为以下3种:①无参的构造函数  ②全缺省的构造函数  ③编译器默认生成的构造函数 

          默认构造函数的共同特点是:不用传参就可以调用

    class Date
    {
    public:
    	//下面2种和 当你不写构造函数时编译器自动生成的默认构造函数只能同时存在1种
        //无参的
    	Date()
    	{
    		_year = 2021;
    		_month = 4;
    		_day = 11;
    	}
        //全缺省的
    	Date(int year = 2021, int month = 4, int day = 11)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };

       ⑦编译器生成的默认的构造函数,对内置类型(int, char, double...)不会做任何处理,但是会针对自定义类型的成员,调用它的构造函数去进行初始

    构造函数调用的2种写法:

    int main()
    {
        //无参时
        Date d;
        //单个参数
    	Date(1);
    	Date d1 = 2;//这种写法会发生隐式类型转换
        //多个参数
        Date(2021, 4, 11);
        Date d2 = {2021, 4, 11};//C++11中才支持的写法
    }

    构造函数与初始化列表

    初始化列表:以冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。

    class Date
    {
    public:
        //初始化列表
    	Date(int year, int month, int day)
    		:_year(year),
    		 _month(month),
    		 _day(day)
    	{}
    
    private:
    	int _year;
    	int _month;
    	int _day;
    };

    初始化列表有什么用?

    初始化列表,顾名思义就是对对象进行初始化的,但是我们已经可以在构造函数体内进行初始化了(通过对成员变量进行赋值来进行初始化),为什么还需要初始化列表?

    这是因为,有些类型的数据无法通过在构造函数体内进行赋值来进行初始化。这样的数据类型有下面3种:

    1. 引用成员变量
    2. const成员变量
    3. 自定义类型成员 (且它的类没有默认构造函数[即,它必须要进行传参])

    上面的三种数据类型有一个共同的特点,它们都要求你在定义变量的时候进行赋值。

    比如,引用成员变量,使用引用的时候必须进行初始化,否则语法就是错误的。

     

    析构函数

    析构函数的作用与构造函数相反,在对象的生命周期结束的时候会自动调用析构函数,完成类的一些资源清理的工作。

    析构函数的特点

    • 析构函数名是在类名的前面加上~
    • 无参,无返回值
    • 一个类中有且只有1个析构函数。如果未显式定义,系统会自动生成默认的析构函数。(如果定义了,则采用显式定义的)
    • 对象生命周期结束时,C++编译系统会自动调用析构函数
    • 编译器生成的默认的析构函数,对内置类型(int, char, double...)不会做任何处理,但是会针对自定义类型的成员,会去调用它的析构函数

     

    析构函数的一般使用情况:

    一般使用在那些涉及到动态内存开辟空间的类中,因为这样的对象需要对其动态开辟的空间进行释放。

    class Stack
    {
    public:
        //构造函数
    	Stack(int n = 3)
    	{
    		_a = (int*)malloc(sizeof(int)*n);
    		_size = 0;
    		_capacity = n;
    	}
        //析构函数
    	~Stack()
    	{
    		free(_a);
    		_size = _capacity = 0;
    	}
    private:
    	int* _a;
    	int _size;
    	int _capacity;
    };

     

    拷贝构造函数

    拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象去创建新的对象时,编译器会自动调用拷贝构造函数。

    拷贝构造函数的特点

    • 拷贝构造函数是构造函数的一个重载
    • 拷贝构造函数的参数只有1个,且必须使用引用传参,如果使用引用传值的形式会引发无限递归

    拷贝构造函数的2种调用方法(完全等价的):

    int main()
    {
    	Date d1(1);
    	//拷贝构造函数
    	Date d2(d1);  //1
    	Date d3 = d1; //2
    
    	return 0;
    }

     

    赋值运算符重载

    在了解赋值运算符重载之前,我们需要先知道什么是运算符重载。

    运算符重载

    运算符重载是具有特殊函数名的函数。

    函数名:关键字operator后面接需要重载的运算符符号(如:operator>)

    函数原型:返回类型 operator操作符 (参数列表)

    注意:

    • operator后面必须跟着的是操作符(这样是不可以的 operator@)
    • 重载操作符必须有一个类类型或者枚举类型的操作数
    • 用于内置类型的操作符,其含义无法改变。(比如内中的整型+,3+5这其中的+的意义不会改变)
    • this指针为限定的第一个形参,也就是this作为第一个操作数
    • .*、::、sizeof、?:、. 这5个操作符无法进行重载。

     

    赋值运算符重载

    class Date
    {
    public:
    	Date(int year = 2021, int month = 4, int day = 11)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    	//赋值运算符重载
    	Date& operator=(const Date& d)
    	{
    		_year = d._day;
    		_month = d._month;
    		_day = d._day;
    		return *this;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };

    注意:赋值运算符重载必须有返回值,如果没有返回值的话,无法解决 a = b = c 这种连续赋值的操作。

    拷贝构造函数与赋值运算符重载

    	Date d1(1);
    	Date d2(0);
    	
    	//赋值运算符重载
    	d2 = d1;     //注意,只有2个操作数都是已经定义过的变量时,才会调用赋值运算符重载
    
    	//拷贝构造函数
    	Date d3(d1);
    	Date d4 = d1;

    浅拷贝

    浅拷贝是你在没有写拷贝构造函数和operator=时,编译器自动调用的默认成员函数。它的功能是将对象以字节的为单位拷贝过去。

     

    取地址与const取地址操作符重载

    这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可(编译器默认的基本就够用了),只有特殊情况,才需要重载,比如想让别人获取到指定的内容。

    class Date
    {
    public:
        //取地址操作符重载
    	Date* operator&()
    	{
    		return this;
    	}
        //const取地址操作符重载
    	const Date* operator&()const
    	{
    		return this;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };

     

    展开全文
  • 详解C++类中的个默认成员函数

    千次阅读 2018-11-30 16:17:22
    在C++98中,如果一个类中什么都没有,简称为空类,系统会自动生成个默认的成员函数,构造函数、析构函数、拷贝构造函数、赋值运算符重载、&amp;操作符重载、const,在C++11中又加入了控制默认函数(=default ,...
  • 除了BP网络外,该函数也可以训练任意形式的神经网络,只要它的传递函数对于权值和输入存在导函数即可。调用格式: [net,TR]=trainbfg(NET,Pd,trainV,valV,testV) info=trainbfg(‘info’) NET是待训练...
  • 以上就是类的六大默认的成员函数,这篇博客主要讲构造函数。剩下的五个成员函数后边会持续更出    构造函数 一.构造函数的定义  构造函数是一个特殊的...
  • C语言中常用的六大输入输出函数

    千次阅读 2020-06-06 10:07:43
    函数:putch() 在使用这个函数的使用要导入系统库#include ① 函数原型:int putch (int c); ② 函数功能:从终端输出一个字符, 且转换成ASCII码返回。 ③ 函数参数:其中c要输出的字符,可以是字符型常量、...
  • exec系列函数

    千次阅读 2015-01-20 18:48:32
    exec替换进程映像exec关联函数组(execl、execlp、execle、execv、execvp) 一,exec替换进程映像 在进程的创建上Unix采用了一个独特的方法,它将进程创建与加载一个新进程映象分离。这样的好处是有更多的余地对两...
  • 正如字面意思,本课程讲解的是一个真正意义上的、企业级的项目实战,主要介绍了企业级应用系统中后端应用权限的管理,其中主要涵盖了六大核心业务模块、十几张数据库表。 其中的核心业务模块主要包括用户模块、部门...
  • 专业函数绘图软件Origin

    万次阅读 多人点赞 2014-11-06 16:02:13
    其次:Excel不垃圾,但在函数绘图方面,比起Origin差远了,用垃圾来形容并不过分,可以问问任何高校老师,他们还会使用Excel出图么?那简直是自己找死。当然Origin也只是在绘图方面比Excel厉害,其它的方面还是比...
  • sqrt()函数详解

    万次阅读 多人点赞 2014-08-03 14:52:15
    虽然有可能你平时没有想过这个问题,不过正所谓是“临阵磨枪,不快也光”,你“眉头一皱,计上心来”,这个不是太简单了嘛,用二分的方法,在一个区间中,每次拿中间数的平方来试验,如果了,就再试左区间的中间数...
  • 高等数学 · 第一章 函数

    千次阅读 多人点赞 2019-05-16 18:46:28
    高等数学·第一章 函数 第一节 实数 第二节 函数的定义及其表示 第三节 函数的几种特性 第四节 反函数和复合函数 第五节 初等函数节 总结
  • C++ 种特殊成员函数

    千次阅读 2015-04-14 21:17:14
    C++定义了几种只能作为类成员函数说明的函数,它们称为“特殊成员”函数。这些函数影响着给定类对象创建、删除、拷贝以及转换成其它类型对象的方法。这些函数的另一个重要的特性是它们可以由编译器隐含调用。 ...
  • C语言文件读写函数总结

    千次阅读 多人点赞 2018-04-30 23:51:59
    1、字符写入文件函数 fputc 2、从文件中读取字符 fgetc 二、字符串的读写 1、字符串写入文件函数 fputs 2、从文件中读取字符 fgets 三、块数据读写 1、向文件中写入块数据fwrite 2、从文件中读取块数据fread ...
  • Hive第天——Hive函数 自己的话:千里之行,始于足下。 每天都要保持前进,我势必要有强劲的实力,再跟明天的自己问好。 开窗函数:累计统计 这类函数叫法很多,包括分析函数、窗口函数、开窗函数、分析窗口函数...
  • SVM支持向量机原理及核函数

    万次阅读 多人点赞 2018-04-07 20:21:18
    SVM支持向量机原理详解及核函数函数的选择 分割超平面: 支持向量: 间距: SVM算法的原理就是找到一个分割超平面,它能把数据正确的分类,并且间距最大!
  • 类的六大默认成员函数

    千次阅读 2016-06-02 15:43:30
    1. 构造函数 如果类的成员变量为私有的,要对这些成员初始化必须调用一个共有的成员函数来进行. 这个共有的成员函数在定义对象的同时会自动执行一次,被调用的函数称为构造函数. 构造函数的特点: 1.函数名与类名...
  • 详解c++中类的个默认的成员函数

    万次阅读 多人点赞 2016-07-06 13:01:35
    构造函数、析构函数、拷贝构造函数、赋值运算符重载函数、取地址操作符重载、const 修饰的取地址操作符重载。 (一)构造函数 构造函数,顾名思义,为对象分配空间,进行初始化。它是一种特殊的成员函数,具有以 下...
  • 【图文详细 】Hive 函数、Hive 函数、Hive 函数

    千次阅读 多人点赞 2018-12-02 14:34:15
    1.hive内置函数 1.1、内容较多,见《Hive 官方文档》  https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF   1.2、测试内置函数的快捷方式:   第一种方式:直接使用,例如:select ...
  • 逻辑函数 统计函数 文本函数1 文本函数2 数学三角函数 查找引用函数 日期时间函数
  • Python 函数 | zip 函数详解

    千次阅读 多人点赞 2020-12-10 11:31:31
    2.7 输出字典中值最大所对应的键 在一个字典当中,求值最大所对应的键时,zip() 函数就派上了用场。代码如下: data = {"张三": 100, "李四": 20, "王五": 500, "赵": 12} obj = zip(data.values(), data.keys()...
  • C语言():函数

    万次阅读 2020-10-06 06:42:02
    函数定义的角度看,函数可分为系统函数和用户定义函数两种: l系统函数,即库函数:这是由编译系统提供的,用户不必自己定义这些函数,可以直接使用它们,如我们常用的打印函数printf()。 l用户定义函数:用以...
  • plot函数有以下几种调用格式: 1)plot(x) a:当x是实向量时,则绘制出以该向量元素的下标(即向量的长度)为横坐标,以该向量元素的值为纵坐标的一条连续曲线 b:当x是实矩阵时,按列绘制出每列元素值对应的下...
  • C语言程序设计第五版 谭浩强 第五版课后答案

    万次阅读 多人点赞 2019-06-16 00:27:29
    第四章 C语言程序设计第五版谭浩强课后习题答案 第五章 C语言程序设计第五版谭浩强课后习题答案 第章 C语言程序设计第五版谭浩强课后习题答案 第七章 C语言程序设计第五版谭浩强课后习题答案 第八章 C语言程序设计...
  • 『Excel』常用五函数汇总

    千次阅读 2020-03-28 10:27:18
    这里对数据分析中常用的excel函数进行分类汇总,共五类:关联匹配类、清洗处理类、逻辑运算类、计算统计类、时间序列类 一、关联匹配类 数据不在同一个excel表或同一个excel表不同sheet中,数据太多,copy麻烦也不...
  • 首先,先将结论告诉大家:round函数采用的是四舍入五成双的计数保留方法,不是四舍五入! 1、什么是四舍入五成双? 四舍入五成双是一种比较科学的计数保留方法。具体的保留方法为:1、...
  • 前端面试题(持续更新中)

    万次阅读 多人点赞 2019-11-06 17:16:33
    闭包就是能够读取其他函数内部变量的函数。 闭包的缺点:滥用闭包函数会造成内存泄露,因为闭包中引用到的包裹函数中定义的变量都 永远不会被释放,所以我们应该在必要的时候,及时释放这个闭包函数本 2.数据类型 ...
  • C语言

    万次阅读 多人点赞 2019-12-18 23:01:50
    C语言 42.C语言是一种计算机高级语言。...47.C语言允许有空函数 48.C程序书写格式,允许一行内可以写几个语句 49.C程序的语句无行号 50.C语言的每个语句的最后必须有一个分号 51.C语言本身没有输入...
  • 析构函数(不能重载,没有参数,一个类只能有一个析构函数。如果没定义,编译器会自动生成一个) 析构函数:创建对象时系统会自动调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数来进行清理...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 479,870
精华内容 191,948
关键字:

六大函数