C++编程进阶5(内联函数、如何降低编译成本、处理继承体系中同名不同参的成员函数、私有虚函数)

本文探讨了C++中的内联函数使用策略,包括其对代码效率的影响,以及何时不应声明为内联。同时,介绍了降低编译成本的方法,如减少编译依赖和封装数据成员。还讨论了处理继承体系中同名不同参函数的两种方式,以及私有虚函数可能导致的多态安全性问题。最后,提醒开发者注意不要将虚函数声明为private。

十七、内联函数

https://blog.youkuaiyun.com/Master_Cui/article/details/106391552中,已经简单的说过内联函数的作用。

函数体较小的内联函数经过编译后,可以生成较小的目标码,但是如果内联函数的函数提很大,那么目标码就会很大,运行起来后,占用的内存就会很多,有可能发生换页并降低缓存命中率,导致程序运行效率变慢。所以,内联函数的函数体不能太大(不要超过10行)。只要内联的函数体较小,内联该函数可以令目标代码更加高效。对于存取函数以及其它函数体比较短,性能关键的函数,鼓励使用内联。

如果一个函数模板所有的实例都应该是内联的,可以将此函数模板声明为inline;否则就应该不要将这个函数声明为inline(不论显式或隐式)。

构造函数和析构函数也不要声明为内联,因为在继承体系中,因为构造函数和析构函数中有隐含成员的创建和销毁,以及基类构造函数和析构函数的调用,所以,构造函数和析构函数往往比表面看起来更长。像下图这样

因为在类内实现的函数默认是内联函数,所以,不要在类内实现构造函数和析构函数。

除了构造析构和超过10行的函数外,也不要将包含循环或switch语句的函数声明为内联函数。

此外,即使将函数声明为inline,在编译时,也不一定会被编译器展开;比如虚函数的调用是在运行期确定的,而内联函数的展开是在编译期进行。虚函数内联的主要原因是基类虚函数的函数体经常为了方便放在类内定义。递归函数即使是inline的也不会被展开,编译器对于递归的内联函数会拒绝内联展开

如果通过内联函数的指针调用内联函数,编译器一般也不会在调用点展开,因为,编译器通常必须为此函数指针指向的函数生成一个函数本体。

这也就是为啥在使用函数对象进行传参时,多使用函数调用运算符,少使用函数指针,见https://blog.youkuaiyun.com/Master_Cui/article/details/112553067

十八、如何降低编译成本

有一些头文件中的代码一般都是这样的

上述代码中的person类存在以下问题:

1、因为存在其他自定义类的对象,所以拷贝和赋值的开销较大

2、Person类和自定义头文件之间形成了编译依赖。任意一个头文件被改变,或这些头文件所依赖的其他头文件有改变,那么每一个含有或使用Person类的文件就得重新编译,连串的编译依赖会导致大量文件被重新编译,增加编译的时间

解决办法

1、将数据成员封装成一个类,并用一个指针指向该数据成员类

2、将person封装成一个抽象类,将具体的实现放在子类中,然后用抽象类的指针指向该子类

 

十九、处理继承体系中同名不同参的成员函数

处理继承体系中同名不同参的成员函数除了在https://blog.youkuaiyun.com/Master_Cui/article/details/109849186中提过的指定作用域的方法

第二种处理方法就是在类中使用using声明

class base
{
public:
	base(){cout<<__func__<<endl;}
	~base(){cout<<__func__<<endl;}
	void func(int init) {cout<<__func__<<"in base"<<endl;}
};
 
class derive:public base
{
public:
	derive(){cout<<__func__<<endl;}
	~derive(){cout<<__func__<<endl;}
	using base::func;//新添加的using声明式
	void func() {
		cout<<__func__<<"in derive"<<endl;
	}
};
 
int main(int argc, char const *argv[])
{
	derive d;
	base *pb=&d;
	pb->func(10);
	d.func(10);
	return 0;
}

在第14行添加新的using声明式之后,编译器发现子类中的函数参数不匹配时,会调用基类中的func,避免了名称遮掩问题

 

二十、私有虚函数

子类继承基类后,将基类中的虚函数重新实现,即使该虚函数的访问权限为private,用户也可以通过多态绕过private

示例

class base
{
public:
	base(){}
	virtual ~base(){}

	virtual void func() {cout<<"func in base"<<endl;}
};

class derive:public base
{
public:
	derive(){}
	~derive(){}

private:
	void func() {cout<<"func in derive"<<endl;} 
};
 
int main(int argc, char const *argv[])
{
	base *bp=new derive();
	bp->func();
	return 0;
}

所以,最好不要把虚函数设置为private。

 

参考

《Effective C++》

 

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值