分类

--友元、static成员

一、友元

友元机制同意一个类将对其非公有成员的訪问权授予指定的函数或类(对未被授权的函数或类,则阻止其訪问);友元的声明以keywordfriend開始,可是它仅仅能出如今类定义的内部。

友元声明能够出如今类中的不论什么地方:友元不是授予友元关系的那个类的成员,所以它们不受其声明出现部分的訪问控制影响。

【最佳实践】

通常。将友元声明成组的放在类定义的開始或结尾是个好主意!

1、友元关系:一个样例

如果一个窗体管理类Window_Mgr可能须要訪问由其管理的Screen对象的内部数据。Screen应该同意其訪问自己的私有成员:

class Screen
{
friend class Window_Mgr;
};

Window_Mgr的成员能够直接引用Screen的私有成员:

Window_Mgr &
Window_Mgr::relocate(Screen::index x,Screen::index c,Screen &s)
{
s.height += r;
s.width += c;
return *this;
}

如果缺少友元声明,这段代码将会出错:将不同意使用形參s的height和width成员。

注:友元能够是普通的非成员函数,或前面定义的其它类的成员。或整个类。

2、使其它类的成员函数成为友元

class Screen
{
//Screen指定仅仅同意relocate成员訪问:
//函数名必须用该函数所属的类名字加以限定!
friend Window_Mgr &Window_Mgr::relocate(Window_Mgr::index,
Window_Mgr::index,
Screen &);
};

3、友元声明与作用域

须要注意友元声明与友元定义之间的互相依赖。

在前面的样例中,类Window_Mgr必须先定义。

否则,Screen类就不能将一个Window_Mgr函数指定为友元。然而,仅仅有在定义类Screen之后,才干定义relocate函数—— 毕竟,它被设为友元是为了訪问类Screen的成员。

更一般地讲,必须先定义包括成员函数的类,才干将成员函数设为友元。

还有一方面,不必预先声明类和非成员函数来将它们设为友元。

友元声明将已命名的类或非成员函数引入到外围作用域中。此外,友元函数能够在类的内部定义,该函数的作用域扩展到包围该类定义的作用域。

class X
{
friend class Y;
friend void f()
{ }
}; class Z
{
Y * ymem;
void g()
{
return ::f();
}
};

4、重载函数与友元关系

类必须将重载函数集中每一个希望设为友元的函数都声明为友元:

class Screen
{
friend std::ostream& storeOn(std::ostream &, Screen &);
// ...
}; //将该函数作为Screen的友元
extern std::ostream& storeOn(std::ostream &, Screen &); //该函数对Screen没有特殊的訪问权限
extern BitMap& storeOn(BitMap &, Screen &);

//P398 习题12.34/35
class Sales_item
{
friend Sales_item add(const Sales_item &item1,
const Sales_item &item2);
friend std::istream &input(Sales_item &,std::istream &);
public: bool same_isbn(const Sales_item &rhs) const
{
return rhs.isbn == isbn;
} Sales_item():units_sold(0),revenue(0) {} private:
std::string isbn;
unsigned units_sold;
double revenue;
}; Sales_item add(const Sales_item &item1,const Sales_item &item2)
{
if (item1.same_isbn(item2))
{
Sales_item item;
item.isbn = item1.isbn;
item.units_sold = item1.units_sold + item2.units_sold;
item.revenue = item1.revenue + item2.revenue;
return item;
} return item1;
} std::istream &input(Sales_item &item,std::istream &in)
{
in >> item.isbn >> item.units_sold >> item.revenue; return in;
}

二、static类成员

通常,static数据成员存在于类类型的每一个对象中。static数据成员独立于该类的随意对象而存在:每一个static数据成员是与类关联的对象,并不与该类的对象相关联!

正如类能够定义共享的static数据成员一样,类也能够定义static成员函数。static成员函数没有this形參,它能够直接訪问所属类的static成员,可是不能直接使用static成员。

1、使用类的static成员的长处

1)static成员的名字是在类的作用域中,因此能够避免与其它类的成员或全局对象名字冲突

2)能够实施封装。static成员能够是私有成员,而全局对象不能够。

3)通过阅读程序easy看出static成员是与特定类关联的。这样的可见性可清晰地显示程序猿的意图。

2、定义static成员

在成员声明前加上keywordstatic将成员设为static。static成员遵循正常的公有/私有訪问规则:

class Account
{
public:
void applyint()
{
amount += amount * interestRate;
} static double rate()
{
return interestRate;
}
static void rate(double); private:
std::string owner;
double amount; //interestRate 对象的值。为Account类型的全体对象所共享
static double interestRate;
static double initRate();
};

3、使用类的static成员

能够通过作用域操作符从类直接调用static成员,或者通过对象、引用或指向该类类型对象的指针间接调用。

    Account ac;
Account *pac = ∾
double rate;
rate = ac.rate();
rate = pac -> rate();
rate = Account::rate();

static成员函数

Account类有两个名为rate的 static成员函数,当中一个定义在类的内部。当我们在类的外部定义static成员时,无须反复指定static保留字,该保留字仅仅出如今类定义体内部的声明处:

void Account::rate(double newRate)
{
interestRate = newRate;
}

1、static成员是类的组成部分但不是不论什么对象的组成部分,因此,static成员函数没有this指针。

2、由于static成员不是不论什么对象的组成部分,所以static成员函数不能被声明为 const。毕竟,将成员函数声明为const就是承诺不会改动该函数所属的对象。

3、最后,static成员函数也不能被声明为虚函数(后面介绍)。

//P400 习题12.38/39/40
class Foo
{
public:
Foo(int Ival):ival(Ival){}
Foo():ival(0){} int get()
{
return ival;
} private:
int ival;
}; class Bar
{
public:
static Foo FooVal()
{
++ callsFooVal;
return foo;
} private:
static int ival;
static Foo foo;
static int callsFooVal;
}; int Bar::ival = 0;
Foo Bar::foo = Foo();
int Bar::callsFooVal = 0;

static数据成员

static数据成员必须在类定义体的外部定义(正好一次)。不像普通数据成员,static 成员不是通过类构造函数进行初始化,而是应该在定义时进行初始化。

保证对象正好定义一次的最好办法,就是将static数据成员的定义放在包括类非内联成员函数定义的文件里。

double Account::interestRate = initRate();

像使用随意的类成员一样,在类定义体外部引用类的static成员时,必须指定成员是在哪个类中定义的。然而,statickeyword仅仅能用于类定义体内部的声明中,定义不能标示为static。

1、特殊的整型const static成员

仅仅要初始化式是一个常量表达式,整型const static 数据成员就能够在类的定义体中进行初始化:

class Account
{
public:
static double rate()
{
return interestRate;
}
static void rate(double); private:
//or: static const int period = 30;
const static int period = 30;
double daily_tb1[period];
};
const int Account::period; //OK
const int Account::period = 30; //Error

【注意:】const static数据成员在类的定义体中初始化时。该数据成员仍必须在类的定义体之外进行定义!

在类内部提供初始化式时,成员的定义就不能再指定初始值了;

2、static成员并非类对象的组成部分

由于static数据成员不是不论什么对象的组成部分,所以它们的一些使用方式对于非static数据成员而言是不合法的。

1)static数据成员的类型能够是该成员所属的类类型。非static成员被限定声明为其自身类对象的指针或引用:

class Bar
{
public:
//... private:
static Bar mem; //OK
Bar *mem1;
Bar &mem2;
Bar mem3; //Error
};

2)static数据成员能够用作默认实參:

class Screen
{
public:
Screen clear(char = bkground); private:
static const char bkground = '#';
};

非static数据成员不能用作默认实參,由于它的值不能独立于所属的对象而使用。

//P402 习题12.42
class Example
{
public:
static double rate; static const int vecSize = 20;
static vector<double> vec;
}; const int Example::vecSize;
double Example::rate = 6.5;
vector<double> Example::vec(vecSize);

//P400 “拓展”习题12.37
class Account
{
public: Account(const std::string &name = "",double Amount = 0):
owner(name),amount(Amount) {} void applyint()
{
amount += amount * interestRate;
} static double rate()
{
return interestRate;
}
static void rate(double); double deposit(double Amount)
{
amount += Amount;
return amount;
} bool withdraw(double Amount)
{
if (Amount > amount)
{
return false;
}
else
{
amount -= Amount;
return true;
}
} double getBalance()
{
return amount;
} private:
std::string owner;
double amount; static double interestRate;
static double initRate();
}; void Account::rate(double newRate)
{
interestRate = newRate;
} double Account::interestRate = 2.5;
double Account::initRate()
{
return 2.5;
}

版权声明:本文博主原创文章。博客,未经同意不得转载。

C++ Primer 学习笔记_53_类和数据抽象 --友元、static员的更多相关文章

  1. C++ Primer 学习笔记_57_类和数据抽象 --管理指针成员

    复印控制 --管理指针成员 引言: 包括指针的类须要特别注意复制控制.原因是复制指针时.一个带指针成员的指针类 class HasPtr { public: HasPtr(int *p,int i): ...

  2. C++ Primer 学习笔记_56_ 类和数据抽象 --消息处理演示示例

    拷贝控制 --消息处理演示样例 说明: 有些类为了做一些工作须要对复制进行控制. 为了给出这种样例,我们将概略定义两个类,这两个类可用于邮件处理应用程序.Message类和 Folder类分别表示电子 ...

  3. C++ Primer 学习笔记_54_类和数据抽象 --拷贝构造函数、赋值运算符

    拷贝控制 --复制构造函数.赋值操作符 引言: 当定义一个新类型时,须要显式或隐式地指定复制.赋值和撤销该类型的对象时会发生什么– 复制构造函数.赋值操作符和析构函数的作用!      复制构造函数: ...

  4. C++学习笔记(2)----类模板和友元

    当一个类包含一个友元声明时,类与友元各自是否是模板是相互无关的.如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例.如果友元自身是模板,类可以授权给所有友元模板实例,也可以只授权给特定 ...

  5. C++ Primer学习笔记(三) C++中函数是一种类型!!!

    C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型! 函数名就是变量!函数名就是变量!函数名就是变量! (---20160618最新消息,函数名不是变量名...囧) (---201 ...

  6. C++ Primer学习笔记(二)

    题外话:一工作起来就没有大段的时间学习了,如何充分利用碎片时间是个好问题. 接  C++ Primer学习笔记(一)   27.与 vector 类型相比,数组的显著缺陷在于:数组的长度是固定的,无法 ...

  7. Java学习笔记——File类之文件管理和读写操作、下载图片

    Java学习笔记——File类之文件管理和读写操作.下载图片 File类的总结: 1.文件和文件夹的创建 2.文件的读取 3.文件的写入 4.文件的复制(字符流.字节流.处理流) 5.以图片地址下载图 ...

  8. python学习笔记4_类和更抽象

    python学习笔记4_类和更抽象 一.对象 class 对象主要有三个特性,继承.封装.多态.python的核心. 1.多态.封装.继承 多态,就算不知道变量所引用的类型,还是可以操作对象,根据类型 ...

  9. Java学习笔记之---类和对象

    Java学习笔记之---类和对象 (一)类 类是一个模板,它描述一类对象的行为和状态  例如:动物类是一个类,动物们都有属性:颜色,动物们都有行为:吃饭 public class Dog { Stri ...

随机推荐

  1. linux下C语言socket网络编程简例

    原创文章,转载请注明转载字样和出处,谢谢! 这里给出在linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到client的连接后,发送数据给client:clie ...

  2. Delphi 的绘图功能(29篇博客)

    http://www.cnblogs.com/del/category/123038.html

  3. 算法起步之Bellman-Ford算法

    原文:算法起步之Bellman-Ford算法 从这篇开始我们开始介绍单源最短路径算法,他是图算法之一,我们前面说的贪心,图的遍历,动态规划都是他的基础,单源最短路径其实说的就是图中节点到节点的最短路径 ...

  4. hdu1495之经典搜索

    非常可乐 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  5. 最佳新秀SSH(十三)——Spring集装箱IOC分析和简单的实现

    时间最近一段时期,"集装箱"这个词一直萦绕在我的耳边,连吃饭.睡在我的脑海里蹦来蹦去的. 由于这几天的交流时间.讨论,对于理解容器逐渐加深. 理论上的东西终归要落实到实践,今天就借 ...

  6. Everything You Wanted to Know About Machine Learning

    Everything You Wanted to Know About Machine Learning 翻译了理解机器学习的10个重要的观点,增加了自己的理解.这些原则在大部分情况下或许是这样,可是 ...

  7. 别样JAVA学习(五)继承上(1.0)Object类equals()

    上一节继承下(一)我们进行抽象类.接口以及多态的学习. 接下来大家我们讲点特殊的东西就是object类, 我们一直在说继承,子继承了父,父还有没有父类呢, 为什么这么思考,大家想构造函数的第一行是不是 ...

  8. silverlight游戏在坑内发展

    最初做<金X>使用silverlight它是由于右手锯的深蓝色silverlight游戏开发教程,在这里,好评,写得很好的教程!基于这样的思想游戏覆盖.你可以给游戏开发商新提供的非常多的思 ...

  9. RequireJS学习资料

    RequireJS学习资料汇总   入门系列 [1]阮一峰 RequireJS用法 [2]RequireJS入门指南 文档系列 [1]RequireJS中文文档 [2]RequireJS英文文档 代码 ...

  10. SE 2014年4月22日(二)

    如图配置: 网络中存在三个公有AS 其中AS200使用了 BGP联盟技术(如图配置) 在AS 100 中R1上起源了四条BGP路由,(1)要求全网BGP设备均能够正常学习 (2)要求:(使用BGP团体 ...