类默认生成的成员函数

类默认生成的六个成员函数

一、构造函数

我们知道,类的数据成员是不能在声明类的时候初始化的,因为类并不是一个实体,而是一种抽象的数据类型,并不占据存储空间。为了解决这个问题,C++提供了构造函数来处理对象的初始化。

1、构造函数的作用

构造函数是一种特殊的成员函数,与其他成员函数不同,构造函数是在对象被实例化的时候自动被调用的,而且只执行这一次,它不能被用户调用。构造函数没有this指针。

构造函数的名字是固定的,与类名相同,不能由用户任意命名,它没有类型,没有返回值。

构造函数的功能是由用户自己定义的,用户根据初始化的要求设计函数体和函数参数。

如果用户自己没有定义构造函数,则C++系统会自动生成一个构造函数,称作默认构造函数或者缺省构造函数。只是这个构造函数是空的,不执行任何操作,但还是会被调用。

例:设计一个日期类,并定义构造函数

classdate
{
public:
                date()             //构造函数
                {
                                _year = 0;     //初始化为0
                                _month = 0;
                                _day = 0;
                }
private:
                int _year;          //一般数据成员以_开头或者以m_开头
                int _month;
                int _day;
};

2、带参的构造函数

有时候用户希望对不同的对象赋予不同的初始值,这时就必须用到带参的构造函数,实现不同的初始化。其对应的实参是在定义对象的时候给定的。

构造函数首部的一般形式:

构造函数名(类型1 形参1,类型2 形参2,...)

因为用户不能调用构造函数,所以实参是在定义对象的时候给出的:

类名 对象名(实参1,实参2,...);

例:

classdate
{
public:
                date(int year ,intmonth,intday)             //构造函数
                {
                                _year =year;
                                _month =month;
                                _day =day;
                }
private:
                int _year;          //一般数据成员以_开头或者以m_开头
                int _month;
                int _day;
};
intmain()
{
                date d1(2016, 7, 19);   //定义一个对象,它有初始值
                system("pause");
                return 0;
}

3、用参数列表对数据成员初始化

C++还提供了一种初始化数据成员的方法——参数初始化表。这种方法不再函数体内对数据成员初始化,而是在函数首部实现。

例:

classdate
{
public:
                date(int year , int month,int day ) :_year(year)
                                , _month(month)
                                , _day(day)
                {
                }
private:
                int _year;          //一般数据成员以_开头或者以m_开头
                int _month;
                int _day;
};

即在原来函数首部的末尾加上一个冒号,然后列出参数的初始化表,并且参数之间以逗号隔开。

为什么会有这种方法呢???

这是因为有些数据成员比如,引用,const修饰的变量必须在创建的时候初始化,所以只能通过初始化列表来初始化。而且这种方法比较高效。

4、构造函数可重载

尽管构造函数可以有多个,但是对于每一个对象来说,建立对象时只执行其中一个构造函数。还有一点需要强调,如果声明一个无参的对象应该写成

date d1;

而不应该写成

date d1();          //这是一个函数声明,类型是date,函数名是d1,参数为空

5、使用默认参数的构造函数

构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,如果用户不指定实参值,编译系统就使形参取默认值。最好在声明构造函数时指定默认值,而不能只在定义构造函数时指定默认值。

在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。

二、拷贝构造函数

1、拷贝构造函数就是用一个已有的对象复制出多个完全相同的对象。

例:date d2(d1); 其作用就是用已有的对象d1去创建出一个新对象d2,并且d1与d2完全相同。

拷贝构造函数也是构造函数,但他只有一个参数(这个参数只能是本类的一个对象),而且采用对象的常引用形式。拷贝构造函数的作用就是将实参对象的各成员值一一赋给新的对象中对应的成员。

例:

classdate
{
public:
                date(int year , int month,int day ) :_year(year)
                                , _month(month)
                                , _day(day)
                {
                }
                date(const date &d)         //拷贝构造函数
                {
                                _year =d._year;
                                _month =d._month;
                                _day =d._day;
                }
private:
                int _year;          //一般数据成员以_开头或者以m_开头
                int _month;
                int _day;
};

注意:拷贝构造函数是从无到有的创建一个新对象。

拷贝构造函数的参数只能是本类对象的引用,如果不是引用的话会引发无穷的递归。

拷贝构造函数是类默认生成的,但是当牵扯到动态内存的时候默认生成的拷贝构造函数就不能满足我们的要求,这时需  要我们自己根据需要定义一个拷贝构造函数。

2、什么时候调用拷贝构造函数?

程序中需要建立一个新的对象,并且用另一个同类的对象初始化它。

当函数的参数为类的对象时。在调用函数时需要将实参对象完整的传递给形参,也就是需要建立一个实参的拷贝。

函数的返回值是类的对象。在函数调用完毕将返回值带回函数调用处时,此时需要将函数中的对象复制一个临时对象返回

三、析构函数

析构函数也是一个特殊的成员函数,它的作用与构造函数相反,它的名字是类名前面加取反“~”符号。它是在对象释放前系统自动调用的。

1、析构函数的作用并不是删除对象,而是在撤销对象时做一些清理工作。比如关闭打开的文件,释放开辟的动态内存等工作。

2、析构函数不返回任何值,没有函数类型,没有参数,因此也不能重载。

3、调用构造函数和析构函数的顺序

因为函数压栈的关系,所以先构造的后析构,后构造的先析构。如果有全局对象或者静态局部对象,则它们在main函数结束或者调用exit函数时2被析构。

四、赋值运算符重载

1、如果已经定义了两个或多个对象,则这些同类的对象之间可以相互赋值,即一个对象的值可以赋给另一个同类的对象。这里所指的对象的值是对象中所有数据成员的值。

对象之间的赋值是通过赋值运算符“=”重载实现的,即将一个对象的值一一复制给另一对象的对应成员。

如:

classdate
{
public:
                date(int year , int month,int day ) :_year(year)
                                , _month(month)
                                , _day(day)
                {
                }
                date operator=(date&d)               //复制运算符重载
                {
                                _year =d._year;
                                _month =d._month;
                                _day =d._day;
                }
private:
                int _year;          //一般数据成员以_开头或者以m_开头
                int _month;
                int _day;
};

对象赋值的一般形式:

对象名1=对象名2;

2、赋值运算符赋值时,类的数据成员中不能包括动态分配的数据,否则在析构的时候会将同一块内存释放多次,产生错误。

3、要区分赋值运算符重载和拷贝构造函数的功能。赋值运算符是对一个已经创建的对象赋值。

五、取地址运算符重载和const修饰的取地址运算符重载

这两个默认的成员函数一般不用重新定义,

例:

classdate
{
public:

                const date * operator&()const
                {
                                return this ;
                }
private:
                int _year;
                int _month;
}

时间: 2024-10-20 03:26:58

类默认生成的成员函数的相关文章

c++基础--c++默认生成的成员函数

class Empty { public: Empty(); // 缺省构造函数 Empty( const Empty& ); // 拷贝构造函数 ~Empty(); // 析构函数 Empty& operator=( const Empty& ); // 赋值运算符 Empty* operator&(); // 取址运算符 const Empty* operator&() const; // 取址运算符 const }; 默认构造函数      析构函数     

类 this指针 const成员函数

C++ Primer 第07章 类 7.1.2 ?Sales_data类的定义如下: #ifndef SALES_DATA_H #define SALES_DATA_H #include <string> #include <iostream> class Sales_data { public: std::string isbn() const {return bookNo;} Sales_data& combine(const Sales_data&); dou

浅析在类模版中构建成员函数时,使用memcpy产生的副作用

一般情况下我们在对类模版中的成员函数进行构建时会经常对一些数据进行复制拷贝,而通常情况下我们都不提倡用memcpy进行拷贝,因为在类模版中所传进来的类型可以是内置类型也可以是非内置类型,除非你在成员函数中使用memcpy前进行类型萃取,否则它所带来的副作用的后果也是很可怕的.memcpy在对内置类型可正常拷贝,而在对非内置类型拷贝时会出现浅拷贝的现象. 下面我们可以通过一个简单的顺序表程序来分析memcpy对非内置类型所产生的副作用: #include<iostream> #include&l

在C++的类中,普通成员函数不能作为pthread_create的线程函数,如果要作为pthread_create中的线程函数,必须是static

在C++的类中,普通成员函数不能作为pthread_create的线程函数,如果要作为pthread_create中的线程函数,必须是static ! 在C语言中,我们使用pthread_create创建线程,线程函数是一个全局函数,所以在C++中,创建线程时,也应该使用一个全局函数.static定义的类的成员函数就是一个全局函数. 更多 参考  http://blog.csdn.net/ksn13/article/details/40538083 #include <pthread.h> #

C++类的定义,成员函数的定义,对象的创建与使用

---恢复内容开始--- 类是一个模板,可用类生成一系列可用的实例.例如 int B就是生成了一个符合int的数据B,类也是一样,使用类名就可以直接生成一个实例, 该实例中包含类中所有的数据类型和对这些数据的操作方法. 首先,创建一个类 class OBJ { private: char Name[MAX]; int Num; float Price; float Total_price; protected: public: } 该类中包含三个部分,私有部分(private).保护部分(pro

类 this指针 const成员函数 std::string isbn() const {return bookNo;}

转载:http://www.cnblogs.com/little-sjq/p/9fed5450f45316cf35f4b1c17f2f6361.html C++ Primer 第07章 类 7.1.2 ?Sales_data类的定义如下: #ifndef SALES_DATA_H #define SALES_DATA_H #include <string> #include <iostream> class Sales_data { public: std::string isbn

Time类的定义(成员函数)

2-2 Time类的定义 Time Limit: 1000MS Memory limit: 65536K 题目描述 通过本题目的练习可以掌握类与对象的定义: 设计一个时间类Time,私有数据成员有hour(时).minute(分).second(秒): 公有成员函数有:setHour(int)设置数据成员hour的值,非法的输入默认为12:setMinue(int)设置数据成员minute的值,非法输入默认为0:setSecond(int)设置数据成员second的值,非法输入默认为0:setT

6——在类的外部定义成员函数

在类定义的外部定义成员函数时,应使用作用域操作符(::)来标识函数所属的类. 即有如下形式: 返回类型 类名::成员函数名(参数列表) { 函数体 } 其中,返回类型.成员函数名和参数列表必须与类定义时的函数原型一致. //Computer.h class Computer //类定义,起到接口作用 { private: char brand[20]; float price; public: //3个public成员函数的原型声明 void print(); void SetBrand(cha

C++笔记007:易犯错误模型——类中为什么需要成员函数

先看源码,在VS2010环境下无法编译通过,在VS2013环境下可以编译通过,并且可以运行,只是运行结果并不是我们期待的结果. 最初通过MyCircle类定义对象c1时,为对象分配内存空间,r没有初始化,其值为乱码,pi为3.1415926,area为乱码. [cin>>c1.r]这个语句为c1.r赋值,假设为10,然后执行[cout<<c1.area<<endl],我们来看,执行cout时是从内存空间中拿c1.area的值,这个值在定义对象时候已经确定是一个乱码值,此