c++类与对象(二)

1.类的6个默认成员函数

一:构造函数

  • 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次。
  • 构造函数是特殊的成员函数,其特征如下:
  1. 函数名与类名相同。
  2. 无返回值。
  3. 对象构造(对象实例化)时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。
class Date
{
public :// 1.无参构造函数Date (){}// 2.带参构造函数Date (int year, int month , int day ){_year = year ;_month = month ;_day = day ;}
private :int _year ;int _month ;int _day ;
};
void TestDate()
{Date d1; // 调用无参构造函数Date d2 (2015, 1, 1); // 调用带参的构造函数// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明// 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象Date d3();
}
  1. 构造函数可以在类中定义,也可以在类外定义。
  2. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
class Date
{
public:void SetDate(int year, int month, int day){_year = year;_month = month;_day = day;}// 如果用户显式定义了构造函数,编译器将不再生成Date (int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};void Test()
{
// 加入没有定义构造函数,对象也可以创建成功,因此此处调用的是编译器生成的默认构造函数Date d;
}
  1. 无参的构造函数和全缺省的构造函数都称为缺省构造函数,并且缺省构造函数只能有一个。
// 缺省构造函数
class Date
{
public:Date(){_year = 1900 ;_month = 1 ;_day = 1;}Date (int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private :int _year ;int _month ;int _day ;
};void Test()
{Date d1;
}

以上测试函数能通过编译吗?
不能,当创建对象d1时,程序不知道d1对象应该调用哪一个构造函数。所以会报错。

析构函数

  • 与构造函数功能相反,在对象被销毁时,由编译器自动调用,完成类 的一些资源清理和汕尾工作。
  • 析构函数是特殊的成员函数,其特征如下:
  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值。
  3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
typedef int DataType;
class SeqList
{
public :SeqList (int capacity = 10){_pData = (DataType*)malloc(capacity * sizeof(DataType));assert(_pData);_size = 0;_capacity = capacity;}~ SeqList(){if (_pData){free(_pData );//释放堆上的空间_pData = NULL; //将指针置为空_capacity = 0;_size = 0;}}
private :int* _pData ;size_t _size;size_t _capacity;
};
  • 注意:析构函数体内不是删除对象,而是做一些对象删除前的相关清理工作。

拷贝构造函数

  • 只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
  • 拷贝构造函数也是特殊的成员函数,其特征如下:
  • 拷贝构造函数是构造函数的一个重载形式。
  • 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。如下图
  • 若未显示定义,系统会默认生成默认的拷贝构造函数。 默认的拷贝构造函数会按照成员的声明顺序依次 拷贝类成员进行初始化。
    **请注意:**对象的赋值都是对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。而对象的复制则是从无到有建立一个新对象,并使它与一个已有的对象完全相同(包括对象的结构和成员的值)。
  • 普通构造函数和拷贝构造函数的区别:
  1. 形式:
类名(形参表列);  //普通构造函数的声明,如Box(int h, int w, int len);
类名(类名& 对象名);  //拷贝构造函数的声明,如Box(Box &b);
  1. 在建立对象时,实参类型不同。系统会根据实参的类型决定调用普通构造函数或拷贝构造函数。
Box box1(12,15,16);  //实参为整数,调用普通构造函数
Box box2(box1);   //实参是对象名,调用拷贝构造函数
  1. 在什么情况下调用
  • 普通构造函数在程序中建立对象时被调用。
  • 拷贝构造函数在用一个已有对象复制一个新对象时被调用。
  • 函数的返回值是类的对象。在函数调用完毕将返回值带回函数调用处时,此时需要将函数中的对象复制一个临时对象并传给该函数的调用处。
Box f()
{Box box1(12,15,18);return box1;
}int main()
{Box box2;box2=f();return 0;
}

赋值操作符重载

  • 运算符重载
  • 运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似,函数名字为:关键字operator后面接需要重载的运算符符号。返回值类型
    operator 需要重载的操作符(参数列表)
class Date
{
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;}Date operator+(int days){Date temp(*this);temp._day += days;return temp;}
private:int _year;int _month;int _day;
};
void Test ()
{Date d(2018, 9, 26);d = d + 10;
}

注意

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

赋值运算符的重载

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}Date& operator = (const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2(d1);Date d3(2018, 10, 27);d2 = d3;
}
  • 赋值运算符主要有四点:
  1. 参数类型
  2. 返回值
  3. 检测是否自己给自己赋值
  4. 返回*this

注意:一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成值的拷贝工作。

哪些运算符不能重载?

  • C++中不能重载的运算符:“?:”、“.”、“::”、“sizeof”和”.*”
  • 原因如下:
  • 在具体讲解各个运算符不能重载之前,先来说明下【重载】:重载的本意是让操作符可以有新的语义,而不是更改语法——否则会引起混乱。
    【注】重载的部分规则:运算符函数的参数至少有一个必须是类的对象或者类的对象的引用。
  1. ?:”运算符,假如能够重载,那么问题来了,看下面的语句:
 exp1?exp2:exp3

该运算符的本意是执行exp2和exp3中的一个,可是重载后,你能保证只执行了一个吗?还是说两个都能执行?亦或两条都不能执行? “?:”运算符的跳转性质就不复存在了,这就是“?:”运算符不能够被重载的最主要原因。

  1. “.”运算符,假如能够重载,那么,问题来了,看下面的例子:
class Y
{
public:void fun();// ...
};
class X
{ // 假设可以重载"."运算符public:Y* p;Y& operator.() { return *p;}void fun();// ...
};
void g(X& x){x.fun(); //请告诉我,这里的函数fun()到底是X的,还是Y的?
}

“.”运算符的本意是引用对象成员的,然而被重载后就不能保证本意,从而带来运算符意义的混淆,如果每个人都这么重载,那更不容易学习C++语言了。

  1. “::”运算符,M::a,该运算符只是在编译的时候域解析,而没有运算的参与进来,由前面【注】重规则可知,如果重载之后,::运算符有了新的语义,那是不是会引起混淆呢?

  2. “sizeof”运算符,该运算符不能被重载的主要原因是内部许多指针都依赖它,举例说明重载的后果:

​​A b[10];//A是类
A* p = &a[3];
A* q = &a[3];
p++;//执行后,p指向a[4],记住是指向a[4]!根据C++规定,该操作等同于p+sizeof(A),此时p应该比q大A类所占字节的大小,事实上,p并不一定会比q大这么多,因为你把sizeof()运算符重载了啊!这时的sizeof(A)并不一定是该类占用的字节大小!
  1. ”.*”引用指向类成员的指针
    以上的5个运算符是不能重载的。

还有两个默认成员函数我没有实现,过两天我会补上。

c++类与对象之默认成员函数相关推荐

  1. 【C++】类和对象的默认成员函数讲解

    文章目录 简介 构造函数※※※ 系统生成的默认构造函数的特性 构造函数的初始化列表 析构函数※ 拷贝构造函数※※※ 默认的拷贝构造函数 赋值重载函数 赋值运算符的重载格式 赋值运算符只能重载成类的成员 ...

  2. 3-3:类与对象中篇——默认成员函数之构造函数和析构函数

    文章目录 一:类的默认6个成员函数 二:构造函数 (1)构造函数的概念 (2)构造函数注意事项 三:析构函数 (1)析构函数的概念 (2)析构函数注意事项 一:类的默认6个成员函数 如果一个类里面什么 ...

  3. 3-5:类与对象中篇——默认成员函数之运算符重载

    文章目录 一:运算符重载 (1)运算符重载 A:为什么要有运算符重载? B:如何进行运算符重载 C:注意 (2)赋值运算符重载 二:const修饰类的成员函数 一:运算符重载 C++ 允许在同一作用域 ...

  4. 3-4:类与对象中篇——默认成员函数之拷贝构造函数

    文章目录 (1)拷贝构造函数的概念 (2)拷贝构造函数的注意事项 (1)拷贝构造函数的概念 拷贝构造函数:用于创建一个与原对象一模一样的对象,也即拷贝构造函数=拷贝+构造函数.拷贝构造函数只有一个形参 ...

  5. 【 C++ 】类和对象(中)—— 类的6个默认成员函数

    目录 1.类的6个默认成员函数 2.构造函数 构造函数概念 构造函数特性 3.析构函数 析构函数概念 析构函数特性 4.拷贝构造函数 拷贝构造函数概念 拷贝构造函数特性 5.赋值运算符重载 运算符重载 ...

  6. 类与对象:类的6个默认成员函数: 构造函数、析构函数、拷贝构造函数、赋值操作符重载、默认拷贝构造与赋值运算符重载的问题、const成员函数、 取地址及const取地址操作符重载

    1.类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类.任何一个类在我们不写的情况下,都会自动生成下面6个默认成员函数. 构造函数 析构函数 拷贝构造函数 赋值操作符重载 const成员函数 ...

  7. [c++ 简单的笔记] 类的6个默认成员函数

    -客亦知夫水与月乎? -哀吾生之须臾 羡长江之无穷. 文章目录 类的6个默认成员函数 构造函数 构造函数初始化列表 注意 explicit关键字(了解) 拷贝构造函数 务必自己写深拷贝的情况的情况 赋 ...

  8. C++类与对象(类中的六大默认成员函数)

    文章目录 类的默认成员函数 构造函数 概念 特征 自己定义构造函数 类中编写 传参方法 编译器自动生成的构造函数 定义变量方式 初始化规则 析构函数 概念 特性 自己定义析构函数 编译器自动生成的析构 ...

  9. 类的6个默认成员函数:构造函数、析构函数、拷贝构造函数、重载运算符、三/五法则

    文章目录 6个默认成员函数 构造函数 概念 默认构造函数的类型 默认实参 概念 默认实参的使用 默认实参声明 全局变量作为默认实参 某些类不能依赖于编译器合成的默认构造函数 第一个原因 第二个原因 第 ...

  10. c++类之“对象包含与成员函数不兼容的类型限定符”与“对象含有与成员 函数 “CarBody::Geta” 不兼容的类型限定符”错误的修改

    首先看一段代码 #include<iostream> using namespace std; int car_num=0; struct position {double x, y; } ...

最新文章

  1. ios集成firebase_如何将Firebase与您的应用程序集成
  2. 数据库安装时挂起问题
  3. Nagios监控系统安装及配置文档
  4. 直播预告 | 共识、区块链和全球一体化经济
  5. 自己喜欢的shell终端配置
  6. java trim 不好使_Java String trim无效
  7. 【Gym 102134-E】Kth subtree【权值树状数组、二分统计第k大+dfs离线操作】
  8. python标准输入多行文字_python如何输入多行数据
  9. KVM 虚拟化技术(理论详解+实战)
  10. 关于ssh整合后struts2拦截器不起作用(blog-1)
  11. w10恢复出厂设置_w10电脑恢复出厂设置 w10电脑恢复出厂设置的方法
  12. Day9-Python文本数据(DataWhale)
  13. word论文格式整理
  14. linux单片机用什么数据库,基于ARM-Linux的SQLite嵌入式数据库的研究 -单片机-电子工程世界网...
  15. Adb使用教程,看了教程后你也是玩机达人啦
  16. 大一微积分笔记整理_大一高数如何做笔记?
  17. 利用python库moviepy,快速剪辑视频
  18. PS CS6视频剪辑基本技巧(一)CS6可以实现的视频剪辑功能
  19. 盛世传承“富三代”品牌让你的家族基业长青
  20. rsyncd.conf 文件man手册翻译

热门文章

  1. vue 多个回调_vue中多层组件间参数的传递、子孙组件回调父组件执行结果
  2. tablayout 增加数字小标_Android中TabLayout添加小红点的示例代码
  3. 冒泡排序及其稳定性介绍
  4. Node:正则验证手机号和身份证号
  5. mysql问题_MySQL 各种问题解决方案(一)
  6. 一个VO(Visual Odometry)的简单实现
  7. karto探秘之open_karto 第三章 --- 扫描匹配
  8. Maven运行报错:-Dmaven.multiModuleProjectDirectory system propery is not set.
  9. Demo(3月28日)
  10. Hadoop step by step _ install and configuration environment