C++有关 const & 内敛 & 友元&静态成员那些事
C++中有关 const & 内敛 & 友元&静态成员 的用法比较杂乱,算是C++中一个麻烦的部分。现速速的对它们做大致的总结,了解它们当中常见的用法和陷阱。
const修饰的成员函数&对象
在成员函数后面加const,const修饰this指针所指向的对象,也就是保证调用这个const成员函数的对象在函数内不会改变
/*************************************************************************
> File Name: 2.cc
> Author: tp
> Mail:
> Created Time: Tue 19 Jun 2018 05:48:12 PM CST
************************************************************************/ #include <iostream>
#include <cstdio>
#include <vector>
using namespace std; class Date
{
public :
Date(int y=, int m =, int d=)
:_year(y),_month( m),_day( d){ } void Display ( )
{
cout<<" Display ( ) " <<endl;
cout<<" year:" <<_year<< endl;
cout<<" month:" <<_month<< endl;
cout<<" day:" <<_day<< endl<<endl ;
}
void Display ( ) const
{
cout<<" Display ( ) const" <<endl;
cout<<" year:" <<_year<< endl;
cout<<" month:" <<_month<< endl;
cout<<" day:" <<_day<< endl<<endl;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
int main( )
{
Date d1;
d1.Display ( ) ;
const Date d2;
d2.Display();
return ;
}
常见情景:
1. const对象可以调用非const成员函数和const成员函数吗?
只能调用const成员函数。因为是const对象,它就要求对象内部数据初始化好不会改变,所以其相应成员函数也应由const修饰。
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std; class Date
{
public :
Date(int y=, int m =, int d=)
:_year(y),_month( m),_day( d){ } void Display ( )
{
cout<<" Display ( ) " <<endl;
cout<<" year:" <<_year<< endl;
cout<<" month:" <<_month<< endl;
cout<<" day:" <<_day<< endl<<endl;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
int main( )
{
// Date d1;
// d1.Display ( ) ;
const Date d2;
d2.Display();
return ;
}
//结果:报错!
2. 非const对象可以调用非const成员函数和const成员函数吗?
都可以调用。调用非const成员函数没有争议,当非const对象调用const成员函数时,对非const对象来说,这其实是一个权限的缩小,是可以完成的。
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std; class Date
{
public :
Date(int y=, int m =, int d=)
:_year(y),_month( m),_day( d){ } void Display ( ) const
{
cout<<" Display ( ) const" <<endl;
cout<<" year:" <<_year<< endl;
cout<<" month:" <<_month<< endl;
cout<<" day:" <<_day<< endl<<endl;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
int main( )
{
Date d1;
d1.Display ( ) ;
// const Date d2;
// d2.Display();
return ;
}
//结果:成功调用
3. const成员函数内可以调用其它的const成员函数非const成员函数吗?
在const成员函数中是不能调用非const成员函数。道理同上
4. 非const成员函数内可以调用其它的const成员函数非const成员函数吗?
非const成员函数既可以掉非const成员函数 也可以调用const成员函数(道理相似,非const成员函数相当于一次权限缩小)
内敛
关于内敛,内敛就是以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方插入代码进行展开,没有
函数压栈的开销,内联函数提升程序运行的效率。
关于内敛的几点注意:
·inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的的函数不适宜使用内联。
·inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
·inline必须和函数定义放在一起,才能成为内联函数,仅仅将inline关键字放到声明前是不起作用的。
·定义在类内的成员函数默认为内联函数。
·debug版本下的内敛函数不展开,所以它可以像普通函数那样进行调试。
class Date
{
public :
void Func () // 定义在类内部默认为内联函数
{}
void Display ();
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
inline void Date::Display () // 成员函数定义为内联
{
cout<<"year:" <<_year<< endl;
cout<<"month:" <<_month<< endl;
cout<<"day:" <<_day<< endl;
}
inline void Test() // 全局函数定义为内联
{}
内敛和宏区别:
·最大的区别在于宏是在预处理阶段处理,而内敛是在编译阶段来进行处理。
·预处理阶段发生宏替换,但替换仅仅是单纯的文本替换,不作类型安全的检查,同时它也不能去访存私有的数据成员;
·而内敛在编译阶段进行的处理,它有类型安全的检查(即调用一个内联函数时,编译器首先确保正确,即所有的参数类型必须是正确的或者编译器必须能够将类型转换为正确类型,并且返回值在目标表达式里应该是正确的类型或者可以改变为正确的类型),同时也可以访存私有的数据成员。
总结来说就是内敛可以像宏一样可以提高代码执行效率,但内敛还可以进行类型安全检查,访问私有数据成员,所以可尽量用内敛去替代宏。
友元
在C++中友元函数允许在类外访问该类中的任何成员,就象成员函数一样,友元函数用关键字friend说明。
关于友元:
1. 友元函数不是类的成员函数。
2. 友元函数可以通过对象访问所有成员,私有和保护成员也一样。
一个典型的例子:
重载自定义类型的输入(>>) 输出(<<)
class Date
{
public :
// operator<<不能为成员函数
// 返回值定义为输入输出流的引用。
friend ostream& operator<< ( ostream& os , const Date& d );
friend istream& operator>> ( istream& is , Date& d);
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
ostream& operator<<( ostream& os , const Date& d)
{
os<<"year:" <<d. _year<<endl ;
os<<"month:" <<d. _month<<endl ;
os<<"day:" <<d. _day<<endl <<endl;
return os ;
}
// cin.operator<<(cin, d1)
istream& operator>> ( istream& is , Date& d)
{
cout<<" 请分别输入年月日: "<<endl ;
is>>d ._year;
is>>d ._month;
is>>d ._day;
return is ;
}
void Test ()
{
Date d1 ;
cin>>d1 ;
cout<<d1 ;
}
为什么说<<, >>操作符重载函数 不能是成员函数?
class Date
{
public :
ostream& operator<< (ostream& os) ;
istream& operator>> (istream& is) ;
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
} ;
ostream& Date::operator<<(ostream& os)
{
os<<" year:" << _year<<endl ;
os<<" month:" << _month<<endl ;
os<<" day:" << _day<<endl <<endl;
return os ;
}
// cin.operator<<( cin, d1)
istream& Date::operator>> (istream& is)
{
cout<<" 请分别输入年月日: " <<endl ;
is>>_year;
is>>_month;
is>>_day;
return is ;
} void Test ( )
{
Date d1 ;
d1>>cin;
d1<<cout;
}
不难注意到最后我们调用>> <<操作符时,将成为一种怪异的操作!估计是难以让人接受的。
究其原因,不难发现其实是由this指针导致的。因为this指针会默认会用成员函数的第一个位置,其它传进来的参数(这里的ostream 、istream)都只能溜到它后面去玩,所以才会致使cin、cout跑到“>>”,"<<"的右边去。想要像正常情况那样使用cin cout,我们就只有不把它们写成成员函数了,这样就没有this指针来抢位子了。但是,这无疑又将引来一个问题:由于函数需要访问传入进来的输入、输出对象,但此时对象的成员是被封装的,函数访问必然就会失败。
所以最后要解决这个问题,我们就只有将“opetator >>”,"operator<<"函数定义为Date类的友元函数了,这样便可通过对象来访问其中的数据成员了,最后完成目的。
从这里也容易看出用友元,其实是一种破坏封装的行为。
除此友元函数之外还有友元类
友元类:整个类可以是另一个类的友元。友元类的每个成员函数都是另一个类的友元函数,都可访问另一个类中的保护或私有数据成员。
静态成员
类里面static修饰的成员,成为静态类成员。它最大的特点就是:类的静态成员是该类型的所有对象对象所共享。
注意:静态成员函数没有隐含的this指针参数,所以可以使用类型::作用域访问符直接调用静态成员函数。

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
class Date
{
public :
Date()
{
cout<<"Date( )"<<endl;
++dCount;
}
static void printCount( )
{
cout<<"Date::dCount:"<<dCount<<endl;;
}
private :
static int dCount;
} ;
//定义并初始化静态成员
int Date::dCount = ;
void Test( )
{
Date d1 ;
d1.printCount( ); //
Date d2 ;
Date d3 ;
//可以直接用类名加类域限定符调用
Date::printCount( ); //
}
关于静态成员一点思考:
1. 静态成员函数可以访问非静态的成员吗?
不可以,因为静态成员函数没有this指针。由于非静态数据成员是存储在对象中,成员函数访问数据成员要借助this指针,所以没有this指针的静态成员函数不能访问非静态数据成员。
2. 非静态的成员函数可以访问静态成员吗?
可以的,静态数据成员存储在地址空间的数据段,它为该类的所有对象共享,这些对象的成员函数自然也可以访问。
C++有关 const & 内敛 & 友元&静态成员那些事的更多相关文章
- c++ 顶层const与底层const
底层const是代表对象本身是一个常量(不可改变): 顶层const是代表指针的值是一个常量,而指针的值(即对象的地址)的内容可以改变(指向的不可改变): #include <iost ...
- C++运算符重载 模板友元 new delete ++ = +=
今天的重载是基于C++ 类模板的,如果需要非类模板的重载的朋友可以把类模板拿掉,同样可以参考,谢谢. 一.类模板中的友元重载 本人喜好类声明与类成员实现分开写的代码风格,如若您喜欢将类成员函数的实现写 ...
- C++学习笔记-const和static
const 1.使用const来定义常量 const int num = 10; //应该在声明时进行初始化,否则该常量的值是不确定的,而且无法修改 2.const与指针 指向常量的指针(const修 ...
- const浅析
前言 c++中使用到const的地方有很多, 而且const 本身也针对不同的类型可能有不同的含义, 比如对指针就有顶层和底层. 本节就是探讨关于C++中const的在不同的地方不同表现或含义. co ...
- 结束C#2的讲解:最后的一些特性
分部类型 可以在多个源文件中为一个类型编写代码.特别适合用于部分代码是自动生成,而其他部分的代码为手动类型. 多个源代码文件组成的类型为分部类型 #region 7-1演示分部类型的混合声明 part ...
- [C++ Primer] 第7章: 类
定义抽象数据类型 定义在类内部的函数是隐式的inline函数. const成员函数 又叫做常量成员函数, 成员函数参数列表之后紧跟const关键字, const修饰的是类this指针. 默认情况下th ...
- C++知识点总结(四)——面向对象的编程细节总结
1.空类的默认函数 一般情况下,对于任意一个类A,如果程序员不显示的声明和定义上述函数,C++编译器将会自动的为A产生4个public inline(公有.内联)的默认函数,这4个函数最常见的形式为: ...
- C++之类的比較运算符的重载
比較运算符的重载通常有两种方式: 第一:作为成员函数重载 曾经几章的Student类为例: <span style="font-family:Microsoft YaHei;font- ...
- C++进阶笔记
思想原则: 以类为例,类最终要处理的是数据,方法只是过程,最终要改变的是private中的数据成员状态.程序设计也是如此,要的是数据. 一.const的作用 const定义变量:定义了一个不可修改的常 ...
随机推荐
- HTML5事件—visibilitychange 页面可见性改变事件
转:https://blog.csdn.net/yusirxiaer/article/details/73480916 又看到一个很有意思的HTML5事件 visibilitychange事件是浏览器 ...
- 破解idea
2019最新注册码 地址: http://idea.lanyus.com/ https://blog.csdn.net/best_luxi/article/details/81479820
- JProfiler 入门教程
推荐文章:JProfiler 入门教程 一.安装JProfiler 从http://www.ej-technologies.com/下载5.1.2并申请试用序列号 二.主要功能简介 1.内存剖析 Me ...
- 学习笔记(一)--->《Java 8编程官方参考教程(第9版).pdf》:第一章到六章学习笔记
注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.违者本人不负法律责任.违法者自负一切法律责任. ...
- JavaScript对象之深度克隆
也不知道从什么时候开始,前端圈冒出了个新词:对象深度克隆.看起来好像很高大上的样子,实际上并不新鲜,在我们的实际项目开发中,你可能早已用到,只不过由于汉字的博大精深,有些原本很简单的事物被一些看似专业 ...
- window 连linux
https://blog.csdn.net/ruanjianruanjianruan/article/details/46954681 https://blog.csdn.net/u013754317 ...
- java控制语句 if-else while do-while for return break continue goto switch default
if for //: object/ForEachFloat.java package object; import java.util.Random; public class ForEachFlo ...
- poj1742 多维背包
普通的多维背包做不了,需要优化一下 但是没有学优化..别的方法也是可以做的 省去一个 表示阶段的 i 维度,dp[j]表示面值为j的钱是否被凑出来了,used[j]表示第i种硬币在凑面值为j的时候被用 ...
- centos下配置DNS
centos网络配置实例 1,配置DNSvi /etc/resolv.conf加入: 代码如下: nameserver 192.168.0.1 nameserver 8.8.8.8 nameserve ...
- JQuery中jsCharts图表插件(十)
一:1.jsCharts图表插件 注意:从官方下来的例子都没指定页面编码,在这种情况下,浏览器就会使用默认设置中文编码:GB2312,GBK等:导致无法执行. 请在html代码中的<head&g ...
