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 & 内敛 & 友元&静态成员那些事的更多相关文章

  1. c++ 顶层const与底层const

    底层const是代表对象本身是一个常量(不可改变):      顶层const是代表指针的值是一个常量,而指针的值(即对象的地址)的内容可以改变(指向的不可改变): #include <iost ...

  2. C++运算符重载 模板友元 new delete ++ = +=

    今天的重载是基于C++ 类模板的,如果需要非类模板的重载的朋友可以把类模板拿掉,同样可以参考,谢谢. 一.类模板中的友元重载 本人喜好类声明与类成员实现分开写的代码风格,如若您喜欢将类成员函数的实现写 ...

  3. C++学习笔记-const和static

    const 1.使用const来定义常量 const int num = 10; //应该在声明时进行初始化,否则该常量的值是不确定的,而且无法修改 2.const与指针 指向常量的指针(const修 ...

  4. const浅析

    前言 c++中使用到const的地方有很多, 而且const 本身也针对不同的类型可能有不同的含义, 比如对指针就有顶层和底层. 本节就是探讨关于C++中const的在不同的地方不同表现或含义. co ...

  5. 结束C#2的讲解:最后的一些特性

    分部类型 可以在多个源文件中为一个类型编写代码.特别适合用于部分代码是自动生成,而其他部分的代码为手动类型. 多个源代码文件组成的类型为分部类型 #region 7-1演示分部类型的混合声明 part ...

  6. [C++ Primer] 第7章: 类

    定义抽象数据类型 定义在类内部的函数是隐式的inline函数. const成员函数 又叫做常量成员函数, 成员函数参数列表之后紧跟const关键字, const修饰的是类this指针. 默认情况下th ...

  7. C++知识点总结(四)——面向对象的编程细节总结

    1.空类的默认函数 一般情况下,对于任意一个类A,如果程序员不显示的声明和定义上述函数,C++编译器将会自动的为A产生4个public inline(公有.内联)的默认函数,这4个函数最常见的形式为: ...

  8. C++之类的比較运算符的重载

    比較运算符的重载通常有两种方式: 第一:作为成员函数重载 曾经几章的Student类为例: <span style="font-family:Microsoft YaHei;font- ...

  9. C++进阶笔记

    思想原则: 以类为例,类最终要处理的是数据,方法只是过程,最终要改变的是private中的数据成员状态.程序设计也是如此,要的是数据. 一.const的作用 const定义变量:定义了一个不可修改的常 ...

随机推荐

  1. Java中的BlockingQueue队列

    BlockingQueue位于JDK5新增的concurrent包中,它很好地解决了多线程中,如何高效安全地“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极 ...

  2. 常见的js算法

    参考地址:链接

  3. SQL表链接

  4. CSS----布局注意事项

    1.当div标签中含有子标签,如果div标签的大小是被div中的子标签撑起来的,那么可能布局(之后)可能就会出现问题(if 父级div中没有border,padding,inlinecontent,子 ...

  5. 使用fidder进行接口测试

    官方下载地址 下载后一路next安装即可. get请求 get请求直接把需要携带的参数使用?跟在后面如:http://127.0.0.1:8000/api/get_event_list/?id=1 p ...

  6. Masm615+notepad++6.8.8搭建汇编开发环境

    前言:很早以前搭过,做了笔记的.现在重新玩汇编,按照笔记撘环境,谁知道坑了自己两个小时,气的我现在打字手都在抖 准备工作: 1.Masm615汇编环境,下载地址:https://pan.baidu.c ...

  7. stl 常用代码

    CString类型的replace ; while((pos = it->m_strFile.find(_T("%UC_INSTALL_ROOT%\\"), pos)) != ...

  8. Linux中查找当前目录下占用空间最大的前10个文件

    du命令 计算出单个文件或者文件夹的磁盘空间占用 -a或--all:包含全部的文件系统: --block-size=<区块大小>:以指定的区块大小来显示区块数目: -h或--human-r ...

  9. 第一个Struts2实例之hello world!

    Struts官网:http://struts.apache.org/ Struts2框架预先实现了一些功能    1:请求数据自动封装    2:文件上传的功能    3:对国际化功能的简化    4 ...

  10. Centos7安装OpenLDAP

    https://www.cnblogs.com/zhaijunming5/p/9522756.html