1、作用域和可见性

1.1 函数原型中的参数其作用域仅在()内。因此参数名称可有可无,但是参数类型需要声明。

1.2 块作用域 在块中声明的标识符其作用域自声明处起,限于块中。

1.3 类作用域 类作用域作用于特定的成员名。如类X的成员M具有类作用域,对M的访问方式如下:

如果在X的成员函数中没有声明同名的局部作用标识符,那么该函数内可以访问成员M;

通过表达式X.M或者X::M以及prt->M访问。 

1.4 在所有类和函数之外出现的声明,具有文件作用域,开始于声明处,结束于文件结尾。

2、可见性  可见性是从对标识符的引用的角度来说的,表示从内层作用域往外层作用域看的时候能看见什么

作用域: 文件作用域>类作用域>块作用域

2.1 标识符声明在前引用在后,如果某个标识符声明在外层,且在内层没有与之同名的标识符,则该标识符在内层可见;

2.2 对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见,也就是在内层被屏蔽。

#include <iostream>
using namespace std;
int i; //全局变量,文件作用域
int main()
{
i=5; //文件作用域的i赋初值
{ //子块1
int i; //局部变量,块作用域
i=7;
cout<<"i="<<i<<endl; //输出7
}
cout<<"i="<<i<<endl; //输出5
}

  

3、对象的生存期  对象从产生到结束的这段时间。在对象生存期内,对象将保持其值,直到被更新。

3.1 静态生存期与程序的运行期相同,在文件作用域中声明的对象具有这种生存期,在函数内部声明静态生存期对象要冠以关键字static;

#include <iostream>
using namespace std;
int i; //全局变量,文件作用域
int main()
{
i=5; //文件作用域的i赋初值,具有静态生存期
cout<<"i="<<i<<endl; //输出5 return 0;
}

  

3.2 动态生存期块作用域中声明的,没有static修饰的对象,通常也称为局部生存期对象,开始于声明点,结束于该标识符的作用域结束处。

#include<iostream.h>
void fun();
int main()
{ fun();
fun();
}
void fun()//静态生存期对象a.第一次被调用a=1,i=5,运算之后a=2,i=6,第二次被调用时,由于a具有静态生存期,a的值保持不变,为2,具有动态生存期的i已经被释放,运算之后a=3,i=6。
{ static int a=1; int i=5;
a++;
i++;
cout<<"i="<<i<<",a="<<a<<endl;
}

  

#include<iostream.h>
int i=1; // i 为全局变量,具有静态生存期。
int main()
{ static int a;// 静态局部变量,有全局寿命,局部可见。
int b=-10; // b, c为局部变量,具有动态生存期。
int c=0;
void other(void);
cout<<"---MAIN---\n";
cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl;
c=c+8; other();
cout<<"---MAIN---\n";
cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl;
i=i+10; other();
}
void other(void)
{
static int a=2;
static int b;
// a,b为静态局部变量,具有全局寿命,局部可见。
//只第一次进入函数时被初始化。
int c=10; // C为局部变量,具有动态生存期,
//每次进入函数时都初始化。
a=a+2; i=i+32; c=c+5;
cout<<"---OTHER---\n";
cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl;
b=a;
}

  

运行结果:
---MAIN---
 i: 1 a: 0 b: -10 c: 0
---OTHER---
 i: 33 a: 4 b: 0 c: 15
---MAIN---
 i: 33 a: 0 b: -10 c: 8
---OTHER---
 i: 75 a: 6 b: 4 c: 15

时钟程序:

#include<iostream>
using namespace std;
class Clock //时钟类定义
{
public: //外部接口
Clock();
void SetTime(int NewH, int NewM, int NewS); //三个形参均具有函数原型作用域
void ShowTime();
~Clock(){}
private: //私有数据成员
int Hour,Minute,Second;
};
//时钟类成员函数实现
Clock::Clock() //构造函数
{
Hour=0;
Minute=0;
Second=0;
}
void Clock::SetTime(int NewH, int NewM, int NewS)
{
Hour=NewH;
Minute=NewM;
Second=NewS;
}
void Clock::ShowTime()
{
cout<<Hour<<":"<<Minute<<":"<<Second<<endl;
}
Clock globClock; //声明对象globClock,具有静态生存期,文件作用域
// 由缺省构造函数初始化为0:0:0
int main() //主函数
{
cout<<"First time output:"<<endl;
//引用具有文件作用域的对象globClock:
globClock.ShowTime(); //对象的成员函数具有类作用域
//显示0:0:0
globClock.SetTime(8,30,30); //将时间设置为8:30:30
Clock myClock(globClock); //声明具有块作用域的对象myClock
//调用拷贝构造函数,以globClock为初始值
cout<<"Second time output:"<<endl;
myClock.ShowTime(); //引用具有块作用域的对象myClock
//输出8:30:30
}

  


4、数据与函数

可以通过函数间的参数传递实现数据共享,更方便的将数据存储在全局对象中,省去了传递的空间,如果将数据和使用数据的函数封装在类中是面向对象的方法。

#include<iostream.h>//使用全局对象实现数据共享,但是使用全局变量会使得程序结构更复杂,而且牵一发而动全身
int global;
void f()
{ global=5;}
void g()
{ cout<<global<<endl;}
int main()
{ f();
g(); //输出“5”
return 0;
}
#include<iostream.h>//将数据和函数封装在类中实现数据共享
class Application
{ public:
void f();void g();
private:
int global;
};
void Application::f()
{ global=5;}
void Application::g()
{cout<<global<<endl;}
int main()
{
Application MyApp;//建立一个新对象来访问函数,该对象似乎不需要改对象,该处有点多余,有待解决(静态成员)
MyApp.f();
MyApp.g();
return 0;
}

  

5、静态成员

静态数据成员 用static声明,属于整个类的成员,并不需要通过对象去访问。该类的所有对象维护该成员的同一个拷贝,必须在类外定义和初始化,用::来指明所属的类。

静态成员函数 类外代码可以使用类名和作用域操作符来调用静态数据成员,静态数据成员函数只能引用属于该类的静态数据成员或者静态数据函数。

#include<iostream.h>
class Application
{ public:
static void f();
static void g();
private:
static int global;
};
int Application::global=0;//在类外初始化
void Application::f()
{ global=5;}
void Application::g()
{cout<<global<<endl;} int main()
{
Application::f();//不建立对象,直接通过类名来访问。
Application::g();
return 0;
}

  

注意事项:静态成员数据和函数属于整个类,不属于任何对象,但是可以通过对象来调用,也可以通过类名来调用。

class A
{
public:
static void f(A a);
private:
int x;
};
void A::f(A a)
{
cout<<x; //对x的引用是错误的
cout<<a.x; //正确
} #include <iostream.h>
class Point //Point类声明
{public: //外部接口
Point(int xx=0,int yy=0){X=xx;Y=yy;countP++;}
Point(Point &p);//拷贝构造函数
int GetX() {return X;}
int GetY() {return Y;}
static void GetC()
{cout<<" Object id="<<countP<<endl;}
private: //私有数据成员
int X,Y;
static int countP;
}
Point::Point(Point &p)
{ X=p.X;
Y=p.Y;
countP++;
}
int Point::countP=0;
int main() //主函数实现
{ Point A(4,5); //声明对象A
cout<<"Point A,"<<A.GetX()<<","<<A.GetY();
A.GetC(); //输出对象号,对象名引用
Point B(A); //声明对象B
cout<<"Point B,"<<B.GetX()<<","<<B.GetY();
Point::GetC(); //输出对象号,类名引用
}

  

6、友元

友元是C++提供的一种破坏数据封装和数据隐藏的机制,包括友元函数和友元类,是通过将一个模块声明为另一个模块的友元,一个模块就能够引用到另个模块中本是被隐藏的信息,为了确保数据的完整性和数据封装与隐藏的原则,建议尽量不使用或少使用友元。

友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体能够通过对象名访问private和protected成员,增加了灵活性,使得程序员可以在封装和快速性方面做合理选择,访问对象中的成员必须通过对象名。

#include <iostream.h>//计算两点距离
#include <math.h>
class Point //Point类声明
{ public: //外部接口
Point(int xx=0, int yy=0) {X=xx;Y=yy;}
int GetX() {return X;}
int GetY() {return Y;}
friend float Distance(Point &a, Point &b); //友元函数
private: //私有数据成员
int X,Y;
};
double Distance( Point& a, Point& b)
{
double dx=a.X-b.X;//在类外通过对象直接访问类point的私有数据成员
double dy=a.Y-b.Y;
return sqrt(dx*dx+dy*dy);
}
int main()
{ Point p1(3.0, 5.0), p2(4.0, 6.0);
double d=Distance(p1, p2);
cout<<"The distance is "<<d<<endl;
return 0;
}

  

若一个类为另一个类的友元,则此类的所有成员都可以访问对方类的私有成员,声明语法:将友元类名在另个类使用friend修饰。

class A
{ friend class B;//友元类
public:
void Display()
{cout<<x<<endl;}
private:
int x;
}
class B
{ public:
void Set(int i);
void Display();
private:
A a;
};
void B::Set(int i)//可以访问并修改A类的私有成员
{
a.x=i;
} void B::Display()
{
a.Display();
}

  

注意事项:友元关系式单向的,如果声明A是B的友元,B的成员函数可以访问A的私有和保护数据,但是反之不然。

7、共享数据的保护

常类型:常类型的对象必须初始化,而且不能被更新,实现对共享数据的保护。

常引用:被引用的对象不能被更新。 const 类型说明符 &引用名

常对象:必须进行初始化,不能被更新。类名 const 对象名

常数组:数组元素不能被更新。 类型说明符 const 数组名[大小]

常指针:指向常量的指针

用const修饰的对象成员

常成员函数:使用const说明,常成员函数不更新对象的数据成员,const是函数类型的一个组成部分,在实现函数的部分也要带const关键字,const也可以用于区分重载函数。通过对象只能调用它的常成员函数,不能通过常对象去调用普通数据函数。

#include<iostream>
using namespace std;
class R
{
public:
R(int r1, int r2){R1=r1;R2=r2;}
void print();
void print() const;//print函数的重载
private:
int R1,R2;
}; void R::print()
{
cout<<R1<<":"<<R2<<endl;
}
void R::print() const
{
cout<<R1<<";"<<R2<<endl;
}
int main()
{
R a(5,4);
a.print(); //调用void print()
const R b(20,52); //定义常对象来调用常成员函数print()
b.print(); //调用void print() const
} #include<iostream>
using namespace std;
class A
{
public:
A(int i);
void print();
const int& r;//常引用
private:
const int a;
static const int b; //静态常数据成员
};
const int A::b=10; //静态常数据成员在类外说明和初始化
A::A(int i):a(i),r(a) //常数据成员只能通过初始化列表来获得初值
{
}
void A::print()
{
cout<<a<<":"<<b<<":"<<r<<endl;
}
int main()
{ A a1(100),a2(0);
a1.print();
a2.print();
}

  

8、编译预处理命令

#include 包含指令 将一个源文件嵌入到当前源文件中该点处。
#include<文件名>  按标准方式搜索,文件位于C++系统目录的include子目录下
#include"文件名"  首先在当前目录中搜索,若没有,再按标准方式搜索。
#define 宏定义指令 定义符号常量,很多情况下已被const定义语句取代。定义带参数宏,已被内联函数取代
#undef 删除由#define定义的宏,使之不再起作用。
条件编译指令    #if 和 #endif
#if  常量表达式
 //当“ 常量表达式”非零时编译
     程序正文 
#endif
......

条件编译指令——#else
  #if   常量表达式
     //当“ 常量表达式”非零时编译
       程序正文1
#else
  //当“ 常量表达式”为零时编译
       程序正文2
#endif
条件编译指令    #elif
#if 常量表达式1
    程序正文1  //当“ 常量表达式1”非零时编译
#elif 常量表达式2
    程序正文2  //当“ 常量表达式2”非零时编译
#else
    程序正文3  //其他情况下编译
#endif

条件编译指令
#ifdef 标识符
    程序段1
#else
    程序段2
#endif

如果“标识符”经#defined定义过,且未经undef删除,则编译程序段1,否则编译程序段2。
条件编译指令
#ifndef 标识符
   程序段1
#else
   程序段2
#endif

如果“标识符”未被定义过,则编译程序段1,否则编译程序段2。
多文件结构

一个源程序可以划分为多个源文件:
类声明文件(.h文件)
类实现文件(.cpp文件)
类的使用文件(main()所在的.cpp文件)
利用工程来组合各个文件。
不使用条件编译的头文件

//main.cpp
#include "file1.h"
#include "file2.h"
int main()
{

} //file1.h
#include "head.h"

//file2.h
#include "head.h"
… //head.h

class Point
{

}

  

使用条件编译的头文件

//head.h
#ifndef HEAD_H
#define HEAD_H

class Point
{

}

#endif
 

C++——程序的结构的更多相关文章

  1. ELF Format 笔记(十一)—— 程序头结构

    ilocker:关注 Android 安全(新手) QQ: 2597294287 程序头表 (program header table) 是一个结构体数组,数组中的每个结构体元素是一个程序头 (pro ...

  2. 黑马程序员——JAVA基础之程序控制流结构之判断结构,选择结构

    ------- android培训.java培训.期待与您交流! ---------- 程序控制流结构:顺序结构:判断结构:选择结构:循环结构. 判断结构:条件表达式无论写成什么样子,只看最终的结构是 ...

  3. Delphi XE5教程5:程序的结构和语法

    内容源自Delphi XE5 UPDATE 2官方帮助<Delphi Reference>,本人水平有限,欢迎各位高人修正相关错误! 也欢迎各位加入到Delphi学习资料汉化中来,有兴趣者 ...

  4. 【Xamarin挖墙脚系列:Xamarin.IOS的程序的结构】

    原文:[Xamarin挖墙脚系列:Xamarin.IOS的程序的结构] 开始熟悉Xamarin在开发IOS的结构!!!!!!! 先看官方 这个是以一个单页面的程序进行讲述的. 1 程序引用的程序集,核 ...

  5. 【Xamarin挖墙脚系列:典型的业务程序的结构搭建】

    原文:[Xamarin挖墙脚系列:典型的业务程序的结构搭建] 其实app就是客户端.在现代的程序中,都是典型的C/S结构.当然,一些离线的小游戏,功能性应用除外,如:电话本,通信录,短信查看等等 这个 ...

  6. 微信小程序开发01 --- 微信小程序项目结构介绍

    一.微信小程序简单介绍: 微信官方介绍微信小程序是一个不需要下载安装就可使用(呵呵,JS代码不用下载吗?展示的UI不用下载吗?)的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用. ...

  7. 毕业设计预习:VHDL入门知识学习(一) VHDL程序基本结构

    VHDL入门知识学习(一) VHDL程序基本结构 简介 VHDL程序基本结构 简介 概念: HDL-Hardware Description Language-硬件描述语言-描述硬件电路的功能.信号连 ...

  8. Java程序的结构和执行

    目录 Java程序的结构 Java程序的执行 source code -- compiler -- class file -- JVM compiler JVM Java语法 数据类型 数据的存储 堆 ...

  9. Android应用程序项目结构

    Android应用程序项目结构 [src]:JAVA源代码目录 [gen]:由系统自动生成的JAVA源码文件,不可修改,只可查看和使用 加载的和依赖的类库 [assets]:本地存储文件的一个文件夹 ...

  10. C语言基础知识-程序流程结构

    C语言基础知识-程序流程结构 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.概述 C语言支持最基本的三种程序运行结构:顺序结构,选择结构,循环结构. 顺序结构:程序按顺序执行, ...

随机推荐

  1. P2813 母舰

    ------------------------------------------- 链接:P2813 ------------------------------------------- 一道贪 ...

  2. Picture POJ - 1177 线段树+离散化+扫描线 求交叉图像周长

    参考  https://www.cnblogs.com/null00/archive/2012/04/22/2464876.html #include <stdio.h> #include ...

  3. Ceph集群网络切换

    背景:需要对已部署好的Ceph集群切换网络,包含包含公共网络和集群网络 1 关闭所有mon节点的mon服务并修改服务器IP systemctl stop ceph-mon@storage01.serv ...

  4. iframe在iphone手机上的问题

    问题1: 通过document.addEventListener("scroll",function(){})对页面滚动监听事件进行监听,但ios下$(document).scro ...

  5. 【易懂】斜率DP

    前言 首先此篇文章是为低年级的朋友准备的,不涉及什么深奥的知识,比如线性规划之类的.仔细看,不要以为自己学不会,看不懂,只要你会DP并打过一些题目而且会单调队列优化DP,斜率DP离你就不远了---.这 ...

  6. gulp常用插件之gulp-uglify使用

    更多gulp常用插件使用请访问:gulp常用插件汇总 gulp-uglify这是一款使用UglifyJS缩小js文件. 更多使用文档请点击访问gulp-uglify工具官网. 安装 一键安装不多解释 ...

  7. Constructing Roads POJ - 2421 最小生成树板子题

    #include<iostream> #include<cstring> #include<algorithm> using namespace std; ; in ...

  8. HTML与W3C

    HTML:超文本标记语言 超文本包括:文字.图片.音频.视频.动画等 流程:写好HTML代码后通过浏览器(自动编译HTML代码)展现出效果 HTML优点: 世界知名浏览器厂商对HTML5的支持 微软 ...

  9. Docker最全教程——从理论到实战(十八)

    前言 VS Code是一个年轻的编辑器,但是确实是非常犀利.通过本篇,老司机带你使用VS Code玩转Docker——相信阅读本篇之后,无论是初学者还是老手,都可以非常方便的玩转Docker了!所谓是 ...

  10. Python之五:函数

    函数会给一段语句块命名,我们可以在任何时候调用它,运行其中的代码 它的一班语法: def fun_name(x): 函数语句体 return a def :说明这是一个函数,我们定义了一个函数: fu ...