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. 编译安装lamp环境

    httpd 2.4.9 + mysql-5.5.33 + php-5.4.29编译安装过程: 准备好以下安装包: mysql-5.5.33-linux2.6-x86_64.tar.gz apr-uti ...

  2. 解决Jmeter插件ERROR: java.io.IOException: Agent is unreachable via TCP的错误

    今天在centos上搭建jmeter监控服务,服务正常启动,我点击run,就在一切看起来很美好的时候,报错了,ERROR: java.io.IOException: Agent is unreacha ...

  3. C++ code:剩余串排列

    方法一: 一种直观的解是,先对第一个字串排序,然后逐个字符在第二个字串中搜索,把搜索不到的字符输出,就是所要的结果. 然而,算法库中有一个集合差运算set_difference,而且要求两个集合容器是 ...

  4. Arrange an Array to Form a Smallest Digit

    /** * Input an array of positive integers, arrange the integers to form new digits, * and output the ...

  5. python 全栈开发,Day76(Django组件-cookie,session)

    昨日内容回顾 1 json 轻量级的数据交换格式 在python 序列化方法:json.dumps() 反序列化方法:json.loads() 在JS中: 序列化方法:JSON.stringfy() ...

  6. python 全栈开发,Day16(函数第一次考试)

    考试题 Python11 期第二次考试(基础数据类型与函数部分) 考试时长:3个小时 满分:105分 一,选择题(每题2分,共24分) 1.python不支持的数据类型有 A.char B.int C ...

  7. C# 读取WAV文件(详细)

    class WAVReader { #region RIFF WAVE Chunk private string Id; //文件标识 private double Size; //文件大小 priv ...

  8. openstack Too many open files错误

    oopenstack突然web页面无法打开,页面报500错误,查看httpd日志报如下错误 [Fri Feb ::] [:error] [pid ] [remote ] IOError: [Errno ...

  9. 【Java】 剑指offer(53-2) 0到n-1中缺失的数字

      本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个 ...

  10. 014 在Spark中完成PV与UV的计算,重在源代码

    1.代码 object LogPVAndUV{ def main(args:Array[String]):Unit={ val conf=new SparkConf() .setMaster(&quo ...