C++ Primer 学习笔记_53_类和数据抽象 --友元、static员
分类
--友元、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员的更多相关文章
- C++ Primer 学习笔记_57_类和数据抽象 --管理指针成员
复印控制 --管理指针成员 引言: 包括指针的类须要特别注意复制控制.原因是复制指针时.一个带指针成员的指针类 class HasPtr { public: HasPtr(int *p,int i): ...
- C++ Primer 学习笔记_56_ 类和数据抽象 --消息处理演示示例
拷贝控制 --消息处理演示样例 说明: 有些类为了做一些工作须要对复制进行控制. 为了给出这种样例,我们将概略定义两个类,这两个类可用于邮件处理应用程序.Message类和 Folder类分别表示电子 ...
- C++ Primer 学习笔记_54_类和数据抽象 --拷贝构造函数、赋值运算符
拷贝控制 --复制构造函数.赋值操作符 引言: 当定义一个新类型时,须要显式或隐式地指定复制.赋值和撤销该类型的对象时会发生什么– 复制构造函数.赋值操作符和析构函数的作用! 复制构造函数: ...
- C++学习笔记(2)----类模板和友元
当一个类包含一个友元声明时,类与友元各自是否是模板是相互无关的.如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例.如果友元自身是模板,类可以授权给所有友元模板实例,也可以只授权给特定 ...
- C++ Primer学习笔记(三) C++中函数是一种类型!!!
C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型! 函数名就是变量!函数名就是变量!函数名就是变量! (---20160618最新消息,函数名不是变量名...囧) (---201 ...
- C++ Primer学习笔记(二)
题外话:一工作起来就没有大段的时间学习了,如何充分利用碎片时间是个好问题. 接 C++ Primer学习笔记(一) 27.与 vector 类型相比,数组的显著缺陷在于:数组的长度是固定的,无法 ...
- Java学习笔记——File类之文件管理和读写操作、下载图片
Java学习笔记——File类之文件管理和读写操作.下载图片 File类的总结: 1.文件和文件夹的创建 2.文件的读取 3.文件的写入 4.文件的复制(字符流.字节流.处理流) 5.以图片地址下载图 ...
- python学习笔记4_类和更抽象
python学习笔记4_类和更抽象 一.对象 class 对象主要有三个特性,继承.封装.多态.python的核心. 1.多态.封装.继承 多态,就算不知道变量所引用的类型,还是可以操作对象,根据类型 ...
- Java学习笔记之---类和对象
Java学习笔记之---类和对象 (一)类 类是一个模板,它描述一类对象的行为和状态 例如:动物类是一个类,动物们都有属性:颜色,动物们都有行为:吃饭 public class Dog { Stri ...
随机推荐
- Java回调理解 (step by step)
在网上搜索了很多篇关于java回调函数的文章,自己也来试了一下写了这篇博客,可能有些地方理解不到位,烦请各位大大指正. 在计算机程序设计中.回调函数.或简称回调.是指通过函数參数传递到其他代码的,某一 ...
- Andy's First Dictionary
Description Andy, 8, has a dream - he wants to produce his very own dictionary. This is not an easy ...
- codeforces 598D Igor In the Museum
题目链接:http://codeforces.com/problemset/problem/598/D 题目分类:dfs 题目分析:处理的时候一次处理一片而不是一个,不然会超时 代码: #includ ...
- delphi 文件的读取(二进制文件和文本文件)
http://blog.csdn.net/earbao/article/details/9174033
- [Android]Eclipse的使用
1.取消Eclipse拼写检查 General -> Editors -> Text Editors -> Spelling 取消enable spell checking 前面的勾 ...
- heapq
heapq-Guest-ChinaUnix博客 假设你需要维护一个列表,这个列表不断有新的元素加入,你需要在任何时候很方便的得到列表中的最大(小)值,因此要求列表始终处于排序完毕状态,怎么办呢 最简单 ...
- mvc action 有多种跳转
在ASP.NET mvc下,action 有多种跳转方式: return RedirectToAction("Index");//一个参数时在本Controller下 如果Redi ...
- 飘逸的python - yield简明教程
发现还有非常多人对yield不理解,云里雾里,于是试着用文字表述. 仅仅要函数含有yield语句,它就返回一个生成器.所以我们与其把其看成函数定义,不如看作是生成器定义.函数用return返回,而生成 ...
- STL 源代码分析 算法 stl_algo.h -- includes
本文senlie原,转载请保留此地址:http://blog.csdn.net/zhengsenlie includes(应用于有序区间) ------------------------------ ...
- 下载jdk文件后缀是.gz而不是.tar.gz怎么办
用chrom浏览器下载了linux版的jdk,发现文件后缀是.gz,没看过这玩意,一打开,还是一个.gz文件,原本以为是新文件后缀呢.那个百度google啊. . ..最后都没发现有这方面的资料啊.. ...