数据的共享与保护(C++面向对象)

5.1标识符的作用域与可见性

2.1.1作用域:一个标识符在程序正文中有效的区域。

1.函数原型作用域(C++中最小的作用域)

在函数原型声明时形参的作用范围

double area(double radius);

标识符radius的作用范围就在函数area形参列表的左右括号之间

2.局部作用域

函数形参列表中形参的作用域:形参列表的声明处——整个函数体结束

函数体内声明的变量:声明处——声明所在的块结束的花括号

局部变量:具有局部作用域的变量

3.类作用域

类X的成员m具有类的作用域

对m的访问方式(3种):

1.成员函数中无同名的标识符 直接m;

2.X.m    X::m(静态变量才使用)

3.ptr->m (ptr为指向X类的一个对象的指针)

4.文件作用域

除了上述情况的   声明点——文件尾

具有文件作用域的变量也称为全局变量

5.命名空间作用域(2种方式)

为避免重名冲突,引入命名空间

1.命名空间::实体名称

2.using namespace 命名空间

6.限定作用域的enum枚举类

(枚举类分为限制作用域和不限制两种)

enum class {…};

enum struct {…};

5.1.2可见性:程序运行到某一点可以引用到的标识符就是该处可见的标识符

作用域和可见性的原则不光适用于变量名,也适用于其他标识符,比如常量名、函数名、枚举类型的取值等

5.2对象的生存期:对象从诞生到结束的时间

分类:静态生存期、动态生存期

5.2.1静态生存期

对象的生存期与程序运行期相同,文件作用域中生命的对象都有静态生存期.

 若要在函数局部作用域中声明具有静态生存期的对象,要用关键字static,特点:不会随函数调用产生副本,也不随函数返回失效(函数的值如果不修改不会改变)

 注意:定义时为指定初始值的基本类型静态生存期变量,默认初始值为0

Static int a;//a=0

5.2.2动态生存期

局部作用域中声明的具有动态生存期的对象 声明点——声明所在块执行完毕

例5-2变量的生存期与可见性

#include<iostream>

using namespace std;

int i=1;//i为全局变量,具有静态生存期

void other()

{

//a,b为静态全局变量,具有全局寿命,局部可见,只第一次进入函数时被初始化

static int a=2;

static int b;

//c 为局部变量,具有动态生存期,每次进入函数时都初始化

int c=10;

a+=2;

i+=32;

c+=5;

Cout<<"OTHER"<<endl;

cout<<"i="<<i<<" a="<<a<<" b="<<b<<" c="<<c<<endl;

b=a;

}

int main()

{

//a 为静态局部变量,具有全局寿命,局部可见

static int a;

//b c 局部变量,具有动态生存期

int b=-10;

int c=0;

cout<<"MAIN"<<endl;

cout<<"i="<<i<<" a="<<a<<" b="<<b<<" c="<<c<<endl;

c+=8;

other();

cout<<"MAIN"<<endl;

cout<<"i="<<i<<" a="<<a<<" b="<<b<<" c="<<c<<endl;

i+=10;

other();

return 0;

}

例5-3具有静态、动态生存期对象的时钟程序

#include<iostream>

using namespace std;

class Clock{

public:

Clock();

void setTime(int newH,int newM,int newS);//三个形参有函数原型作用域

void showTime();

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;//具有静态生存期,文件作用域

int main()

{

cout<<"frist time output"<<endl;

globClock.showTime();//函数的成员函数具有类作用域

globClock.setTime(8,30,30);

Clock myClock(globClock);//具有块作用域

cout<<"second time output:"<<endl;

myClock.showTime();

return 0;

}

5.3.1静态数据成员

如果某个属性为整个类所共有,不属于任何一个具体对象,则采用static关键字来声明为静态成员,静态成员在每个类只有一份,由该类所有对象共同维护和使用。

具有静态生存期

访问方式:类名::标识符

 类的定义中声明,还要在类的外部声明,初始化在类内或者类外(原因:需要以这种方式专门分配空间,而非静态成员不需要是因为他们的空间是与他们所属对象的空间同时分配的)

还有一点就是如果一个类T存在类型为T的静态私有对象,那么可以引用该类的私有构造函数将其初始化(在对类的静态私有数据成员初始化的同时,可以引用该类的其他私有成员)

 注意:在vc6.0中 只能在类外初始化

他的存在是为了对象间的共同交流。

 静态成员函数Static member function 是为了调用static data member 而存在。Compile 不为他分配this 指针,所以他不能调用对象 的非static data member。当你非要调用 非Static data member 时,只要 指明对象就行了(因为没有compile 没有为类的static member function 指定 this 指针,所以引用 非静态成员变量时分不清是哪个对象的,当你指明对象来调用不就行了。)

加了static 限制符的data member or member function 只是限制了调用的权利,并没有限制 被调用的权利。非static 的对象和非static的member function 都可以调用他们。

原文链接:https://blog.youkuaiyun.com/zxxyyxf/article/details/6432612

来自 <https://blog.youkuaiyun.com/zxxyyxf/article/details/6432612>

例5-4具有静态数据成员的Point类

#include<iostream>

using namespace std;

class Point

{

public:

Point(int x=0,int y=0):x(x),y(y){

count++;

}

Point(Point &p){

x=p.x;

y=p.y;

count++;

}

~Point(){count--;}

int getx(){return x;}

int gety(){return y;}

void showCount(){

cout<<"Object count="<<count<<endl;

}

private:

int x,y;

static int count;

const static int origin;

};

int Point::count=0;

const int Point::origin=0;

int main()

{

Point a(4,5);

cout<<"Point A:"<<a.getx()<<","<<a.gety();

a.showCount();

Point b(a);

cout<<"Point B:"<<b.getx()<<","<<b.gety();

b.showCount();

return 0;

}

5.3.2静态函数成员

静态成员函数:用static关键字声明的函数成员

 作用:直接访问该类的静态数据和函数成员。(注意:访问非静态成员,必须通过对象名)

class A{

public:

static void f(A a);

private:

int x;

};

void A::f(A a)

{

cout<<x<<endl;//错误

cout<<a,x<<endl;//正确

}

可以看出通过静态函数访问非静态函数成员相当麻烦,一般静态函数用来访问同一个类中的静态数据成员,维护对象之间共享的数据。

同静态数据成员一样也属于整个类,由同一个类的对象共有、共享

调用方式:

1.类名(常用)

2.对象名

好处:不依赖任何对象,直接访问静态数据。

#include<iostream>

using namespace std;

class Point

{

public:

Point(int x=0,int y=0):x(x),y(y){

count++;

}

Point(Point &p){

x=p.x;

y=p.y;

count++;

}

~Point(){count--;}

int getx(){return x;}

int gety(){return y;}

static void showCount()//静态函数成员

{

cout<<"Object count="<<count<<endl;

}

private:

int x,y;

static int count;//静态数据声明

};

int Point::count=0;//静态数据定义和初始化,使用类名限定

int main()

{

Point a(4,5);//定义对象a,其构造会使count增加1

cout<<"Point A:"<<a.getx()<<","<<a.gety();

Point::showCount();

Point b(a);//定义对象b,其构造会使count增加1

cout<<"Point B:"<<b.getx()<<","<<b.gety();

Point::showCount();

return 0;

}

5.4类的友元

首先说明:

1.友元关系是不能传递的

2.友元关系友元关系是单向的

3.友元关系不能被继承

友元关系就是一个类主动声明哪些其他类或者函数是他的朋友,进而给它们提供对本类的访问特许(也就是:通过友元关系,一个普通函数或者类的成员函数可以访问封装于另外一个类中的数据。)

友元类中的函数自动成为友元函数

语法:函数前面加上friend关键字

友元函数的函数体中可以通过对象名访问类的私有和保护成员

例5-6友元函数计算两点间的距离

#include<iostream>

#include<cmath>

using namespace std;

class Point

{

public:

Point(int x=0,int y=0):x(x),y(y){}//构造函数

int getx(){return x;}

int gety(){return y;}

friend float dist(Point &p1,Point &p2);

private:

int x,y;

};

float dist(Point &p1,Point &p2)

{

double x=p1.x-p2.x;

double y=p1.y-p2.y;

return static_cast<float>(sqrt(x*x+y*y));

}

int main()

{

Point myp1(1,1),myp2(4,5);

cout<<"the distance is:";

cout<<dist(myp1,myp2)<<endl;

return 0;

}

5.4.2友元类

class B

{

...

friend class A;

...

};

A类的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员。

//友元类

1.

#include<iostream>

#include<cmath>

using namespace std;

class A{

public:

A(int xx):x(xx){}//构造函数

void display(){cout<<x<<endl;}

int getx(){return x;}

friend class B;

private:

int x;

};

class B{

public:

B(A &a1):a(a1){}//构造函数

void set(int i);

void display();

private:

A a;

};

void B::set(int i)

{

a.x=i;

}

void B::display()

{

cout<<a.x<<endl;

}

int main()

{

A a(2);

a.display();

int b;

b=a.getx();

cout<<b<<endl;

B c(a);

c.set(3);

c.display();

return 0;

}

2.

class A

{

public:

void distplay(){cout<<x<<endl;}

int getx(){return x;}

friend class B;

private:

int x;

};

class B

{

public:

void set(int i);

void distplay();

private:

int A a;

};

void B::set(int i)

{

a.x=i;

}

5.5共享数据保护

对于既需要共享又需要防止改变的数据就应该声明为常量

5.5.1常对象

常对象必须进行初始化,而且不能更新

语法:const 类型说明符 对象名;

5.5.2const修饰的类成员

1.常成员函数

语法:类型说明符 函数名(参数表)const;

 注意:1.如果将一个对象声明为常对象,则通过该对象只能调用它的常成员函数,而不能调用其他成员函数;

2.常成员函数不能更新目的对象(无论是否通过常对象调用常成员函数,常成员函数运行期间,目的对象都视为常对象)的数据成员,也不能针对目的对象调用该类中没有const修饰的成员函数

//共享数据保护

//常对象必须初始化,且不能被更新

//格式:const 类型说明符 对象名;const放在类型名后面也行

//例如:

/*

//1.

class A

{

public:

A(int i,int j):x(i),y(j){}

private:

int x,y;

};

const A a(3,4);//a是常对象,不可以被更新

//2.

const int n=10;//正确,用10对常量n进行初始化

n=20;//错误,不能对常量进行赋值

*/

例5-7常成员函数举例

#include<iostream>

using namespace std;

class R{

public:

R(int r1,int r2):r1(r1),r2(r2){}

void print();

void print()const;

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();

const R b(20,52);

b.print();

return 0;

}

2.常数据成员

 如果在一个类中说明了常数据成员,那么任何函数都不能对该成员赋值构造函数对该成员初始化只能通过初始化列表。

例5-8常数据成员举例

#include<iostream>

using namespace std;

class A{

public:

A(int i);

void print();

private:

const int a;

static const int b;//静态常数据成员

};

const int A::b=10;

A::A(int i):a(i){}

void A::print(){

cout<<a<<":"<<b<<endl;

}

int main()

{

A a1(100),a2(0);

a1.print();

a2.print();

return 0;

}

注意:类的静态变量和常量都应该在类外定义,但有个例外:类的静态常量如果具有整数类型或者枚举类型,那么可以直接在类定义中为它指定常量值。例外中的例外情况:如果程序中要对这个静态变量或者常量取地址,则不能不在类外定义,因为要为它分配内存

5.5.3常引用

如果在引用时用const 修饰,被声明的引用就是常引用。

常引用所引用的对象不能被更新。

作用:1常引用作形参,不会发生对实参的更改。

2可以绑定到常对象,普通引用不可以

注意:其实常引用不管绑定的是不是常对象,都按照常对象来对待,对于基本类型的引用不能更改他的值,对于类类型的引用不能修改它的数据成员,也不能调用用他的非const的成员函数

语法:const 类型说明符 &引用名

//例5-9常引用做形参

#include<iostream>

#include<cmath>

using namespace std;

class Point{

public:

Point(int x=0,int y=0):x(x),y(y){}

int getx(){return x;}

int gety(){return y;}

friend float dist(const Point &p1,const Point &p2);

private:

int x,y;

};

float dist(const Point &p1,const Point &p2)

{

double x=p1.x-p2.x;

double y=p1.y-p2.y;

return static_cast<float>(sqrt(x*x+y*y));

}

int main()

{

const Point myp1(1,1),myp2(4,5);

cout<<"the distance is:";

cout<<dist(myp1,myp2)<<endl;

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值