C++中的赋值操作符重载和拷贝构造函数
1,关于赋值的疑问:
1,什么时候需要重载赋值操作符?
2,编译器是否提供默认的赋值操作符?
2,关于赋值的疑问:
1,编译器为每个类默认重载了赋值操作符;
1,意味着同类型的类对象可以相互赋值;
2,默认的赋值操作符仅完成浅拷贝;
3,当需要进行深拷贝时必须重载赋值操作符;
1,和拷贝构造函数相同;
4,赋值操作符与拷贝构造函数有相同的存在意义;
3,默认赋值操作符重载编程实验:
1,main.cpp 文件:
#include <iostream>
#include <string> using namespace std; class Test
{
int* m_pointer;
public:
Test()
{
m_pointer = NULL;
}
Test(int i)
{
m_pointer = new int(i);
}
Test(const Test& obj)
{
m_pointer = new int(*obj.m_pointer);
}
Test& operator = (const Test& obj)
{
if( this != &obj ) // 避免自赋值;
{
delete m_pointer;
m_pointer = new int(*obj.m_pointer);
} return *this;
}
void print()
{
cout << "m_pointer = " << hex << m_pointer << endl;
}
~Test()
{
delete m_pointer;
}
}; int main()
{
Test t1 = ;
Test t2; t2 = t1; // 默认赋值操作符的浅拷贝使得两个对象内部指针指向同一片空间; int i = ; // C 语言中允许这样,所以 C++ 中也必须允许;
i = i; t2 = t2; // C++ 中也要允许自赋值,但是没有意义; t1.print();
t2.print(); return ;
}
2,输出结果:
m_pointer = 0x9387008
m_pointer = 0x9387018
3,赋值操作符重载注意事项:
1,赋值操作符返回值一定是引用,为了连续赋值;
2,参数类型一定是 const Type&;
3,不能自赋值;
4,返回当前对象;
4,关于赋值的疑问:
1,如果要进行深拷贝,拷贝构造函数和赋值操作符的实现都要自定义;
5,一般性原则:
1,重载赋值操作符,必然要实现深拷贝;
1,实现深拷贝和自定义赋值操作符及拷贝构造函数是充要条件;
6,数组类的优化编程实验:
1,IntArray.h 文件:
#ifndef _INTARRAY_H_
#define _INTARRAY_H_ class IntArray
{
private:
int m_length;
int* m_pointer; IntArray(int len);
IntArray(const IntArray& obj);
bool construct();
public:
static IntArray* NewInstance(int length);
int length();
bool get(int index, int& value);
bool set(int index ,int value);
int& operator [] (int index);
IntArray& operator = (const IntArray& obj);
IntArray& self();
~IntArray();
};
2,首先写出赋值操作符注意事项模板:
IntArray& IntArray::operator = (cosnt IntArray& obj)
{
if( this != &obj )
{ } return *this;
}
3,函数实现:
IntArray& IntArray::operator = (const IntArray& obj)
{
if( this != &obj )
{
int* pointer = new int[obj.m_length]; if( pointer )
{
/* 复制参数对象中的元素 */
for(int i=; i<obj.m_length; i++)
{
pointer[i] = obj.m_pointer[i];
} /* 深拷贝 */
m_length = obj.m_length;
delete[] m_pointer;
m_pointer = pointer;
}
} return *this;
}
4,main.cpp 文件:
#include <iostream>
#include <string>
#include "IntArray.h" using namespace std; int main()
{
IntArray* a = IntArray::NewInstance();
IntArray* b = IntArray::NewInstance(); if( a && b )
{
IntArray& array = a->self();
IntArray& brray = b->self(); cout << "array.length() = " << array.length() << endl;
cout << "brray.length() = " << brray.length() << endl; array = brray; cout << "array.length() = " << array.length() << endl;
cout << "brray.length() = " << brray.length() << endl;
} delete a;
delete b; return ;
}
5,输出结果:
array.length() =
brray.length() =
array.length() =
brray.length() =
6,使用二阶构造后,拷贝构造函数是私有的,拷贝构造函数就没有作用了,不允许拷贝构造,但是应该重载赋值操作符重载;
7,编译器默认提供函数:
1,虽然类中什么都没写,但是编译器会放四个函数实现进去;
8,下面的代码输出什么?为什么?
1,代码示例:
string s = "";
const char* p = s.c_str(); // 返回字符指针,代表 C 语言中的字符串; cout << p << endl; s.append("abced"); cout << p << endl;
9,字符串问题 1 编程实验:
1,main.cpp 文件:
#include <iostream>
#include <string> using namespace std; int main()
{
string s = "";
const char* p = s.c_str(); // 只有这一行用了 C 方式; cout << p << endl; s.append("abced"); // p 成为了野指针 cout << p << endl; return ;
}
2,这段代码混合了 C 和 C++ 的方式,出了意想不到的错误;
10,关于 string 的疑问 1:
1,string 对象内部维护了一个指向数据的 char* 指针,这个指针可能在程序 运行的过程中发生改变,我们尽量不要操作这个指针;
2,执行 s.append() 函数后,char* 指针指向了新的堆空间 0xFF445566,而将旧的堆空间 0xFF112233 释放,此时 p 指针成了野指针;
3,学习 C++,并且用的是标准库中的内容,所以现在采用的编程思想就应该是 C++ 编程思想,不要混合使用 C 和 C++ 思想;
11,下面的程序输出什么?为什么?
1,代码示例:
const char* p = ""; // p 可以用字符串对象代替;
string s = ""; // 混合了,该注意了; s.reserve(); // 不要使用 C 语言中的方式操作 C++ 中的字符串
for(int i=; i<; i++)
{
s[i] = p[i];
} if( !s.empty() )
{
cout << s << endl;
}
2,没有输出;
12,字符串问题 2 编程实验:
1,main.cpp 文件:
#include <iostream>
#include <string> using namespace std; int main()
{
const char* p = "";
string s = ""; s.reserve(); // 不要使用 C 语言中的方式操作 C++ 中的字符串
for(int i=; i<; i++)
{
s[i] = p[i];
} if( !s.empty() ) // 打印不出;
{
cout << s << endl;
} cout << s << endl; // 打印不出; for(int i=; i<; i++) // 可以打印;
{
cout << s[i] << endl;
} return ;
}
2,更改程序为:
#include <iostream>
#include <string> using namespace std; int main()
{
const string p = "";
string s = ""; s = p; cout << s << endl; return ;
}
3,C++ 工程中,尽量避免指针使用,字符串类出现就是为了替代字符指针;
13,关于 string 的疑问 2:
14,小结:
1,在需要进行深拷贝的时候必须重载赋值操作符;
1,也要重新定义拷贝构造函数;
2,赋值操作符和拷贝构造函数有同等重要的意义;
3,string 类通过一个数据空间保存字符串数据;
4,string 类通过一个成员变量保存当前字符串的长度;
5,C++ 开发时尽量避开 C 语言中惯用的编程思想;
1,字符串类得到的是字符串对象,直接用成员函数操作这个对象就可以,不需要用 C 语言中的 for 循环之类的;
C++中的赋值操作符重载和拷贝构造函数的更多相关文章
- 析构函数-复制构造函数-赋值操作符重载-默认构造函数<代码解析>
通过下面primer中的一道习题,可以更深刻的了解,析构函数,复制构造函数,赋值操作符重载,默认构造函数的使用. 但是我的结果与primer习题解答里面的并不相同,可能是编译器不同的原因导致. // ...
- C#中如何利用操作符重载和转换操作符
操作符重载 有的编程语言允许一个类型定义操作符应该如何操作类型的实例,比如string类型和int类型都重载了(==)和(+)等操作符,当编译器发现两个int类型的实例使用+操作符的时候,编译器会生成 ...
- C#中如何利用操作符重载和转换操作符 (转载)
操作符重载 有的编程语言允许一个类型定义操作符应该如何操作类型的实例,比如string类型和int类型都重载了(==)和(+)等操作符,当编译器发现两个int类型的实例使用+操作符的时候,编译器会生成 ...
- C++中的数组操作符重载
1,本文讲述数组操作符重载,上篇博文的字符串类 string 确实强大,但 string 类 对象还具备 C 方式字符串的灵活性吗?还能直接访问单个字符吗? 1,C 方式字符串灵活性是指能够通过数组 ...
- C++与java中的赋值操作符
#include <iostream> using namespace std; class BankAccount{ private: double balance; public: B ...
- python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域
http://my.oschina.net/leejun2005/blog/145911 http://www.cnblogs.com/lulipro/p/5060163.html http://ww ...
- [c++基础]3/5原则--拷贝构造函数+拷贝赋值操作符
/* * main.cpp * * Created on: Apr 7, 2016 * Author: lizhen */ #include <iostream> #include &qu ...
- C++ 拷贝构造函数和赋值构造函数
转自:http://blog.chinaunix.net/uid-28662931-id-3496326.html 一.拷贝构造函数 int main(int argc, char * argv[]) ...
- C++构造函数详解(复制构造函数 也是 拷贝构造函数)
构造函数是干什么的 该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作,故:构造函数的作用:初始化对象的数据成员. 构造函数的种类 1 class Com ...
随机推荐
- R语言-八皇后问题
老师给我出了个暑期作业:用R语言解决八皇后问题. 八皇后问题:国际象棋棋盘(8×8)上放8个“后”,使8个“后”之间互相不能被进攻.(即:每个“后”所在行.列.两条斜线都没有其它子) 查看网上,大多用 ...
- 【leetcode】Sliding Puzzle
题目如下: On a 2x3 board, there are 5 tiles represented by the integers 1 through 5, and an empty square ...
- UVa 572 Oil Deposits (Floodfill && DFS)
题意 :输入一个m行n列的字符矩阵,统计字符“@”组成多少个八连块.如果两个字符“@”所在的格子相邻(横竖以及对角方向),就是说它们属于同一个八连块. 分析 :可以考虑种子填充深搜的方法.两重for循 ...
- Shell中Bash的基本功能(二)
1 历史命令 1)历史命令的查看[root@localhost ~]# history [选项] [历史命令保存文件]选项:-c: 清空历史命令-w: 把缓存中的历史命令写入历史命令保存文件.如果不手 ...
- 进程and线程and协程效率对比
1.进程与进程池的效率对比 多进程:p.start()过程中,只是向操作系统发送一个信号,至于什么时候执行,都是操作系统的事情,操作系统接收到信号时,帮该进程申请一块内存空间+拷贝父进程的地址空间 # ...
- Linux基本命令使用(一)
1.head -n 文件 可以查看文件前n行 tail -n 文件 可以查看文件的后n行 tail -f 文件 可以实时查看文件,比如日志在更新,就可以实时显示最后几行 ...
- 3D Computer Grapihcs Using OpenGL - 14 OpenGL Instancing
如果我们需要绘制两个(或者多个)一样的立方体(或者物体),只是位置.缩放.旋转不一样,那么我们可以不需要多次将这个物体的顶点信息.颜色信息等发送到显卡,而是发送一次,绘制多次,仅仅是每次绘制之前应用不 ...
- windows下开启远程连接Mysql
使用“Ctrl + R”组合键快速打开cmd窗口,并输入“cmd”命令,打开cmd窗口. 使用“mysql -uroot -proot”命令可以连接到本地的mysql服务. 使用“use mysq ...
- css命名和书写规范
前言 在项目开发中对于css名字的命名和书写老是感觉很混乱,这对于代码的可读性以及维护提出了挑战,所以在闲暇之余看了一些这方面的内容,现总结如下... 1.命名规则说明 所有的命名最好都小写 属性的值 ...
- node.js npm 操作 模块化开发 cnpm镜像安装
模块(包) 传统引入 js 的缺点 整个网页,我们写了一个 js 文件,所有的特效都在里面 耦合度太高,代码之间关联性太强,不便于后期维护 变量容易 全局污染 如果将 复杂的 js 文件,拆成多个功能 ...