通过一个例子来复习C++操作符重载及隐式成员函数。MyString类模仿标准string类,简单的实现了构造一个字符串、字符串比较、取单个字符等功能。如下:

#ifndef MYSTRING_H_
#define MYSTRING_H_
#include <iostream>
using std::ostream;
class MyString
{
public:
//默认构造函数
MyString(void);
//析构方法
~MyString(void);
//构造函数
MyString(const char *s);
//复制构造函数
MyString(const MyString & s);
//重载赋值操作符
MyString & operator=(const MyString & st);
MyString & operator=(const char * s); //友元函数非成员函数,重载<<操作符
friend ostream & operator<< (ostream & os, const MyString & str); //返回字符串长度
int length() const{return len;};
//将比较函数作为友元,使String对象可以与常规的C字符串进行比较
// if("cm" == st) -> if (operator==("cm",st)) -> if (operator==(MyString("cm"),st))
friend bool operator< (const MyString & st, const MyString & dst);
friend bool operator> (const MyString & st, const MyString & dst);
friend bool operator== (const MyString & st, const MyString & dst); //使用[]表示法来取字符
//返回 char & 便可以给特定元素赋值 MyString st = "cm"; st[0] = 'j';
char & operator[] (int i){return str[i];};
//给const MyString对象使用的[]版本
const char & operator[](int i) const {return str[i];}; //静态成员方法,属于类,只能访问静态成员变量
static int HowMany(){return num_strings;}; private:
char *str;
int len;
//不能在类声明中初始化静态成员变量
static int num_strings;
};
#endif //MyString.cpp
#include <iostream>
#include "MyString.h"
using std::cout; int MyString::num_strings = 0; MyString::MyString(void)
{
len = 0;
str = new char[len + 1];
str[0] = '\0';
num_strings++;
} MyString::~MyString(void)
{ --num_strings;
delete [] str;
} MyString::MyString(const char *s)
{
len = std::strlen(s);
str = new char[len + 1];
std::strcpy(str,s);
num_strings++;
} MyString::MyString(const MyString & s)
{
num_strings++;
len = s.len;
str = new char[len + 1];
std::strcpy(str,s.str);
} MyString & MyString::operator=(const MyString & st)
{
//防止将对象赋给自身
if (this == &st)
return *this;
delete [] str; //先释放原有的字符串
len = st.len;
str = new char[len + 1];
std::strcpy(str,st.str);
return *this; //返回自身引用,以便可以连续赋值,eg:S0 = S1 = S3
} MyString & MyString::operator= (const char * s)
{
delete [] str; //先释放原有的字符串
len = std::strlen(s);
str = new char[len + 1];
std::strcpy(str,str);
return *this;
} ostream & operator<< (ostream & os, const MyString & str)
{
os << str.str;
return os;
} bool operator< (const MyString & st, const MyString & dst)
{
return (std::strcmp(st.str,dst.str) > 0);
}
bool operator> (const MyString & st, const MyString & dst)
{
return (dst < st);
}
bool operator== (const MyString & st, const MyString & dst)
{
return (std::strcmp(st.str,dst.str) == 0);
}

 隐式成员函数

C++自动提供以下成员函数:

1、默认构造函数,如果没有定义构造函数

2、复制构造函数

3、赋值操作符

4、默认析构函数

5、地址操作符

其中隐式地址操作符返回调用对象的地址(this指针),一般不考虑它,默认析构函数不执行任何操作。重点关注前三个成员函数。

(1)默认构造函数

如果没有提供任何构造函数,C++将创建默认构造函数,如果定义了构造函数,C++将不再定义默认的构造函数,默认构造函数一般是不带参数的,但带参数的构造函数也可以是默认构造函数,只要所有的参数都有默认值。

(2)复制构造函数

复制构造函数用于将一个对象复制到新创建的对象中,原型如下:

Class_name(const Class_name &);

当函数按值传递对象或函数返回对象时,都将使用复制构造函数。

新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用,这可能取决与编译器的实现。

默认复制构造函数的功能:

逐个复制非静态成员(浅复制)

当类中包含了使用new初始化的指针成员时,默认复制构造函数就会出现问题,这时,应当显式定义一个复制构造函数,以复制指向的数据(深度复制)。如MyString类的复制构造方法:

MyString::MyString(const MyString & s)
{
num_strings++;
len = s.len;
str = new char[len + 1];
std::strcpy(str,s.str);
}

(3)赋值操作符

C++允许类对象赋值,这是通过自动为类重载赋值操作符实现的。原型如下:

Class_name & Class_name::operator=(const Class_name &);

当已有的对象赋给另一个对象时,将是使用重载的赋值操作符。

赋值操作符的隐式实现也是对成员逐个进行复制。当默认赋值操作符不合适的时候,就应当显式定义赋值操作符。

如:

MyString & MyString::operator=(const MyString & st)
{
//防止将对象赋给自身
if (this == &st)
return *this;
delete [] str; //先释放原有的字符串
len = st.len;
str = new char[len + 1];
std::strcpy(str,st.str);
return *this; //返回自身引用,以便可以连续赋值,eg:S0 = S1 = S3
}

自定义赋值操作符应注意一下事项:

1)由于目标对象可能引用了以前分配的数据,所以应当先释放这些数据

2)函数应当避免将对象赋给自身

3)返回一个指向调用对象的引用,以便可以进行连续赋值。

总结:

当类中含有指针成员时,应当注意的事项:

1、如果在构造函数中使用new来初始化指针成员,则应当在析构函数中使用delete来释放

2、new与delete必须相互兼容,new对应delete, new[] 对应delete[]

3、应当自定义一个复制构造函数,进行深度复制。

4、自定义赋值操作符,通过深度复制将一个对象复制给另一个对象。

该函数应当完成以下功能:

检查自我赋值情况,释放成员指针以前指向的内存,复制数据而不仅仅是数据的地址,要返回一个指向调用对象的引用。

C++学习笔记-隐式成员函数的更多相关文章

  1. Scala学习笔记--隐式转换

    隐式转换的规则:1.无歧义规则:隐式转换唯有不存在其他可插入转换的前提下才能插入  若编译器有两种方法修正x+y 如convert1(x)+y,convert2(x)+y,会报错2.单一调用规则:只尝 ...

  2. C++转换构造函数和隐式转换函数 ~ 转载

    原文地址: C++转换构造函数和隐式转换函数 用转换构造函数可以将一个指定类型的数据转换为类的对象.但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个Complex类对象转换成doubl ...

  3. C++转换构造函数和隐式转换函数

    今天是第一次听到C++还有个转换构造函数,之前经常见到默认构造函数.拷贝构造函数.析构函数,但是从没听说过转换构造函数,隐式转换函数也是一样,C++的确是够博大精深的,再次叹服!          其 ...

  4. Hadoop源码学习笔记(2) ——进入main函数打印包信息

    Hadoop源码学习笔记(2) ——进入main函数打印包信息 找到了main函数,也建立了快速启动的方法,然后我们就进去看一看. 进入NameNode和DataNode的主函数后,发现形式差不多: ...

  5. objective-C学习笔记(四)函数成员:方法(函数)

    函数分为:  全局函数(C语言函数) 成员函数(OBJC方法):实例方法 “-” 和类方法“+”的区别 //这里要区别静态变量(类变量).全局函数.常量的区别 OBJC里面,所有方法默认为公有方法.没 ...

  6. js学习日记-隐式转换相关的坑及知识

    隐式转换比较是js中绕不过去的坎,就算有几年经验的工程师也很有可能对这块知识不够熟悉.就算你知道使用===比较从而避免踩坑,但是团队其它成员不一定知道有这样或那样的坑,有后端语言经验的人常常会形成一个 ...

  7. STL学习笔记--关联式容器

    关联式容器依据特定的排序准则,自动为其元素排序.缺省情况下以operator<进行比较.set multiset map multimap是一种非线性的树结构,具体的说是采用一种比较高效的特殊平 ...

  8. 学习笔记之——C语言 函数

    采用函数的原因: 随着程序规模的变大,产生了以下问题: --main函数变得相当冗杂 --程序复杂度不断提高 --代码前后关联度提高,修改代码往往牵一发而动全身 --变量使用过多,命名都成了问题 -- ...

  9. JavaScript学习笔记(七)——函数的定义与调用

    在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意! 如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/ ...

随机推荐

  1. javah 错误: 找不到 'com.example.tony.gpiojni.JNITest' 的类文件

    在 android studio的Terminal中运行javah转换.class文件为.h文件失败, 提示: 错误: 找不到 'com.example.tony.gpiojni.JNITest' 的 ...

  2. 【vijos】1006 晴天小猪历险记之Hill(dijkstra)

    https://vijos.org/p/1006 连边后跑点权的最短路 注意连边的时候左端点可以连到下一行的右端点,右端点可以连到下一行的左端点 #include <cstdio> #in ...

  3. 多线程编程(三)--创建线程之Thread VS Runnable

    前面写过一篇基础的创建多线程的博文: 那么本篇博文主要来对照一下这两种创建线程的差别. 继承Thread类: 还拿上篇博客的样例来说: 四个线程各自卖各自的票,说明四个线程之间没有共享,是独立的线程. ...

  4. 【NLP+Deep learning】好文

    http://blog.jobbole.com/77709/ 原文出处: http://colah.github.io/posts/2014-07-NLP-RNNs-Representations/

  5. eclipse中打开含有汉字的properties文件显示乱码

    http://blog.csdn.net/wangjun5159/article/details/46965831

  6. [SDOI2016 Round1] 征途[斜率优化]

    2225. [SDOI2016 Round1] 征途 ★★★☆   输入文件:menci_journey.in   输出文件:menci_journey.out   简单对比时间限制:1 s   内存 ...

  7. datatables如何把列设置成hidden隐藏域?

    官网:https://datatables.net/reference/option/设置: visible: false如下: <!DOCTYPE html><html>&l ...

  8. 03.Curator深入使用

    1.Apache Curator简介     Curator提供了一套Java类库,可以更容易的使用ZooKeeper.ZooKeeper本身提供了Java Client的访问类,但是API太底层,不 ...

  9. 【教程】AI画放射图

    第一步:画矩形作图宇宙键shift 第二步:分为网格 第三步:直接选择工具 第四步:填充交叉色,这步不再敖述: 第五步:视图--轮廓:快捷键ctrl+y; 第六步:直接选择工具选择除边框以外的所有节点 ...

  10. Yii框架2.0的小部件

    小部件是视图里的可重用单元. 小部件是在视图中使用的,但是可能需要使用控制器传给他的模型,比如在渲染表单的时候.比如一般的时间拾取器就可以直接砸视图里加入如下代码就可以: <?php use y ...