C++学习笔记-隐式成员函数

通过一个例子来复习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、自定义赋值操作符,通过深度复制将一个对象复制给另一个对象。

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

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

时间: 2024-10-12 22:40:45

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

scala学习笔记-隐式转换与隐式参数(18)

Scala提供的隐式转换和隐式参数功能,是非常有特色的功能.是Java等编程语言所没有的功能.它可以允许你手动指定,将某种类型的对象转换成其他类型的对象.通过这些功能,可以实现非常强大,而且特殊的功能. Scala的隐式转换,其实最核心的就是定义隐式转换函数,即implicit conversion function.定义的隐式转换函数,只要在编写的程序内引入,就会被Scala自动使用.Scala会根据隐式转换函数的签名,在程序中使用到隐式转换函数接收的参数类型定义的对象时,会自动将其传入隐式转

Scala学习笔记--隐式转换

隐式转换的规则:1.无歧义规则:隐式转换唯有不存在其他可插入转换的前提下才能插入  若编译器有两种方法修正x+y 如convert1(x)+y,convert2(x)+y,会报错2.单一调用规则:只尝试一个隐式操作,编译器不会把x+y重写成convert1(convert2(x))+y3.显式调用规则:若编写的代码没有错误,则不会尝试任何隐式操作4.命名隐式转换:隐式转换可以任意命名

C++学习笔记26,虚函数

在C++里面,虚函数是一类重要的函数!可以通过虚函数定义不同对象同一行为的不同实现. 举一个简单的例子: #include <iostream> #include <string> using namespace std; class Animal{ protected: string name; public: Animal(const string &s):name(s){ } virtual ~Animal(){ } virtual void speak()const

python学习笔记11-python内置函数

python学习笔记11-python内置函数 一.查看python的函数介绍: https://docs.python.org/2/library/ 二.python内置函数 1.abs获取绝对值: 通过python官网查看abs abs(x) Return the absolute value of a number. The argument may be a plain or long integer or a floating point number. If the argument

Vue学习笔记进阶篇——Render函数

本文为转载,原文:Vue学习笔记进阶篇--Render函数 基础 Vue 推荐在绝大多数情况下使用 template 来创建你的 HTML.然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这就是 render 函数,它比 template 更接近编译器. <h1> <a name="hello-world" href="#hello-world"> Hello world! </a> </h1>

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

Hadoop源码学习笔记(2) ——进入main函数打印包信息 找到了main函数,也建立了快速启动的方法,然后我们就进去看一看. 进入NameNode和DataNode的主函数后,发现形式差不多: public static void main(String args[]) {     try {       StringUtils.startupShutdownMessage(DataNode.class, args, LOG);       DataNode datanode = crea

C++学习笔记22,普通函数重载(1)

转载请注明出处:http://blog.csdn.net/qq844352155/article/details/31353325 该博文仅用于交流学习,请慎用于任何商业用途,本博主保留对该博文的一切权利. 博主博客:http://blog.csdn.net/qq844352155 什么是方法重载? 方法重载也可以说是函数重载,函数的多态性. 具体来说就是将函数或者方法的名称用于多个函数,但是参数的类型或者参数的数目不同. 在这篇blog里面我只讨论类外函数的重载. 例如一个简单的例子: #in

jQuery源码学习笔记:扩展工具函数

// 扩展工具函数 jQuery.extend({ // http://www.w3school.com.cn/jquery/core_noconflict.asp // 释放$的 jQuery 控制权 // 许多 JavaScript 库使用 $ 作为函数或变量名,jQuery 也一样. // 在 jQuery 中,$ 仅仅是 jQuery 的别名,因此即使不使用 $ 也能保证所有功能性. // 假如我们需要使用 jQuery 之外的另一 JavaScript 库,我们可以通过调用 $.noC

初探swift语言的学习笔记(类对象,函数)

swift扩展了很多功能和属性,有些也比较奇P.只有慢慢学习,通过经验慢慢总结了. 下面将初步学习一下类的写法. 码工,最大爱好就是看码,而不是文字,太枯燥. // // computer.swift // swiftDemo // // Created by apple on 14-6-8. // Copyright (c) 2014年 fengsh. All rights reserved. /* 写本例子的目的在于快速学习swift类的写法,包括知识点: 1.属性设置 2.构造.释构 3.