浅谈c++之面向对象程序设计的几种小技巧系列之第一部分

  既然说是浅谈C++之面向程序设计,那么本次我会和大家分享面向对象设计中经常使用的几种类型:1.conversion function(转换函数)、2.non-explicit-one-argument-ctor、3.explicit-one-argument-ctor、4.pointer-like class(智能指针)、5.Function-like class(仿函数)、6.namespace(命名空间)、7.class template(类模板)、8.Function template(函数模板)、9.member template(成员模板)、10.specialization(模板特化)、11.partial specialization(模板偏特化)、12.template template parameter (模板模板参数)、13.关于C++标准库、14.variadic template(since C++11)、15.reference、16.复合&继承关系下的构造函数和析构函数。


  下面对上述列出的C++小技巧进行展开说明:


  注:本次文章将前3中小技巧作为本次《浅谈C++之面向对象程序设计的几种小技巧》系列的第一部分进行说明,对于剩下的其他十三种小技巧请参照《浅谈C++之面向对象程序设计的几种小技巧》系列的后续的文章。谢谢!


  • *** 1.conversion function (转换函数):***

  我们知道class(类)是C++中重要的一个机制,对于我所说的转换函数,在C++中往往有两种形式,一种是将:class(类)转出去;另一种是将外界的东西转化成class(类)。对于我说的这两种大家可能不是太明白,下面结合程序做进一步的说明:

#include<iostream>
using namespace std;
//如下:将class转出去,通过利用operator将class(类)原本的类型转化成另一种类型
class Fraction{
public:
	Fraction(int num, int den = 1) :
		m_num(num), m_den(den){}
	operator double()const{   //将数据类型为的 Fraction 的数据转化成 double 类型数据
		return static_cast<double>(m_num)/ static_cast<double>(m_den);
	}
private:
	int m_num;
	int m_den;
};
int main()
{
	Fraction f(3, 5);//对象f
	double d = 3+f;//编译器将自动将对象f转化成double型
	return 0;
}

  上述类Fraction之所以会转化成double类型,是因为在类Fraction中编译器自动自动调用类Fraction中的转化函数operator double() const{}实现函数转化(将class转出去)。


  对于重载函数(转化函数)operator double() const{},其中double()表示Fraction类转化后的类型(转化后为double型),小括号里面无参数;返回类型不需要要写(因为在转化前并不知道会将其转化成什么类型,如果贸然写上返回类型,容易在写返回类型时将类型写错,从而造成编译的错误,那么干脆不写,因为返回类型就是转化后的类型。


  同时大家可能会注意到,重载函数(转化函数)中的const,之所以在函数后面加const是因为该函数体在执行的过程中不会改变函数体中的参数值。也就是说在类中被const声明的成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.所以加上const。那么有的人可能会问,如果不加可不可以。我的回答是可以,但是最好加上,而且对于有些程序来说,不加const的话有可能会造成不可预知的程序错误。类中的const成员函数的目的是为了指明哪个成员函数可以在const对象上被调用。


  通过上述我们知道了函数转化的一种方法:将class转出去。如果写的时候认为合理的话,可以给类写好几个转化函数。刚才说了,对于转化函数有两种,上述只是介绍了其中的一种,并且我们平时说的转化函数也往往就是指这一种,而另一种转化函数——将别的东西转化成这种类(class)就是下面要给大家介绍的non-explicit-one-argument-ctor。


  • *** 2.non-explicit-one-argument-ctor:***

  通过名字可以知道,这是一种只有的一个实参的构造函数,并且构造函数前面不加explicit。


  对于C++中的构造函数前面加关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生,说明构造器只能被明确的调用。申明为explicit的Ctor(构造函数)不能在隐式转换中使用。C++中,一个参数的构造函数,承担了两个角色。a.构造函数;b.是个默认且隐含的类型转换操作符。


  介绍完explicit的作用后,我们言归正传继续介绍non-explicit-one-argument-cotr这种类型的转化(将外界其他类型的东西转化成class(类)的类型。同样我们还是通过一段程序来进行说明。

#include<iostream>
using namespace std;
//如下:将class转出去,通过利用operator将class(类)原本的类型转化成另一种类型
class Fraction{
public:
	Fraction(int num, int den = 1) :
		m_num(num), m_den(den){}//此构造函数有一个实参den=1
	 Fraction  operator + (const Fraction & f){   //将数据类型为的 Fraction 的数据转化成 double 类型数据
		return Fraction((this->m_num)+(f.m_num)*(this->m_den),this->m_den);
	}
	 int getNum()const{ return m_num; }
	 int getDen()const{ return m_den; }
private:
	int m_num;
	int m_den;
};
int main()
{
	Fraction f(3, 5);
	Fraction d = f+3;
	cout << "(" << d.getNum() << "," << d.getDen() << ")"<<endl;
	return 0;
}

  上述程序的输出结果为:d=(18,5)


  从上述的程序可以看出,这是一种隐式转换,将 Fraction d = f+3;中的3通过构造函数进行隐式转化成(3,1)其类型为 Fraction 类型。再通过运算符(“+”)进行重载,完成 Fraction 类的对象相加的操作。


  通过上述程序,相信已经可以窥探到:non-explicit-one-argument-cotr  的奥义了。同时也会知道explicit关键字在构造函数中的作用。为了加深对explicit这个关键字的理解,下面我们在构造函数的前面加上explicit进行比对,也就是我接下来要说的explicit-one-argument-ctor……


  • 3.explicit-one-argument-ctor:

  对于将class(类)转出去[即所说的conversion function (转换函数)],以及将外界其他类型的东西转化成class(类)的类型[即所说的non-explicit-one-argument-ctor]。那么如果给ctor(构造函数)加上explicit后会如何呢。


  下面我们介绍在ctor(构造函数)前面加上关键字explicit后会如何,通过关键字的名字————explicit可以知道,加上这个关键字之后,构造函数将只能通过显式调用,而不能像上面我么你说的第二种情况进行隐式调用。


  为了将其说的更清晰,还是选择通过一段程序来进行讲解。

#include<iostream>
using namespace std;
//如下:将class转出去,通过利用operator将class(类)原本的类型转化成另一种类型
class Fraction{
public:
	explicit Fraction(int num, int den = 1) ://将构造函数前面加上关键字explicit后,该构造函数将变成只能通过显示调用。
		m_num(num), m_den(den){}
	operator double()const{   //将数据类型为的 Fraction 的数据转化成 double 类型数据
		return static_cast<double>(m_num) / static_cast<double>(m_den);
	}
	Fraction  operator + (const Fraction & f){   //将数据类型为的 Fraction 的数据转化成 double 类型数据
		return Fraction((this->m_num) + (f.m_num)*(this->m_den), this->m_den);
	}
private:
	int m_num;
	int m_den;
};
int main()
{
	Fraction f(3, 5);
	Fraction d1 = f + 4; //Error C2440:"初始化“:无法从”double“转换为Fraction”
	double d = 3 + f;
	cout << d << endl;
	return 0;
}

  上面的这段程序编译时将会出现错误,且它的错误提示为    Error C2440:"初始化“:无法从”double“转换为Fraction”。这时候需要思考程序为什么会出现这种错误的提示:因为在构造函数的前面加上了explicit,使构造函数:

explicit Fraction(int num, int den = 1) :
		m_num(num), m_den(den){}

  只能通过显式进行调用,而不能进行隐式调用(即不能够通过构造函数将数字“4”转换成Fraction(4,1),也就是说当构造函数前面加上了关键字explicit后,这种隐式的转化是不被允许的。


  以上部分就是本次文章《浅谈C++之面向对象程序设计的几种小技巧》的第一部分的全部内容,对于其他的三种小技巧,请见《浅谈C++之面向对象程序设计的几种小技巧》系类的后续文章。谢谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值