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定义变量:定义了一个不可修改的常 ...
随机推荐
- ArrayList源码分析笔记(jdk1.8)
1.特点: ArrayList 是一个动态数组,它是线程不安全的,允许元素为null 可重复,插入有序 读写快,增删慢 扩容:默认容量 10,默认扩容1.5倍 建议指定容量大小,减少扩容带来的性能消耗 ...
- winform(记事本的打印)
- Webpack中的css-loader 和style-loader
传统上我们会在html文件中引入CSS代码,借助webpack style-loader和css-loader我们可以在.js文件中引入css文件并让样式生效. style-loader和css-lo ...
- vue修饰符学习
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- HDU 5988 Coding Contest(费用流+浮点数)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5988 题目大意: 给定n个点,m条有向边,每个点是一个吃饭的地方,每个人一盒饭.每个点有S个人,有B盒 ...
- js有关事件驱动
事件驱动 /* 什么是事件? 1.事件发生了 2.我要对这个事件做对应的处理 ...
- 【转】ssh服务器启动和客户端常用操作
前言 简单的来说,SSH 是 Secure SHell protocol 的简写 (安全的壳程序协议),它可以透过数据封包加密技术,将等待传输的封包加密后再传输到网络上, 因此,数据讯息当然就比较安全 ...
- PHP PC端微信扫码支付【模式二】详细教程-附带源码(转)
博主写这破玩意儿的时候花了大概快两天时间才整体的弄懂逻辑,考虑了一下~还是把所有代码都放出来给大家~抱着开源大无私的精神!谁叫我擅长拍黄片呢?同时也感谢我刚入行时候那些无私帮过我的程序员们! 首先还是 ...
- java12小时制的时间转换为24小时制
Java中将12小时制的时间转换为24小时制的方式如下: import java.text.SimpleDateFormat; import java.util.Date; public class ...
- 2733: [HNOI2012]永无乡
题解: 爬到了bzoj的数据哈哈哈哈 然后提交上去t了 自己测只有1秒多呀 不理解 然后这题目就是个线段树/平衡树合并裸题 来练一下线段树合并 据说是nlogn的 #include <bits/ ...