成员函数、非成员函数和友元函数介绍
- 格式:wps
- 大小:25.00 KB
- 文档页数:3
友元函数及友元类已有 20621 次阅读 2009-5-9 15:43 |个人分类:C/C++什么是友元(friend)?允许另一个类或函数访问你的类的东西。
友元可以是函数或者是其他的类。
类授予它的友元特别的访问权。
通常同一个开发者会出于技术和非技术的原因,控制类的友元和成员函数(否则当你想更新你的类时,还要征得其它部分的拥有者的同意)。
分清成员函数,非成员函数和友元函数成员函数和非成员函数最大的区别在于成员函数可以是虚拟的而非成员函数不行。
所以,如果有个函数必须进行动态绑定,就要采用虚拟函数,而虚拟函数必定是某个类的成员函数。
关于这一点就这么简单。
如果函数不必是虚拟的,情况就稍微复杂一点。
Ø类的主要特点之一是数据隐藏,即类的私有成员只能在类定义的范围内使用,也就是说私有成员只能通过它的成员函数来访问。
Ø但是,有时候需要在类的外部访问类的私有成员。
为此,就需要寻找一种途径,在不放弃私有数据安全性的情况下,使得类外部的函数或类能够访问类中的私有成员,在C++中就用友元作为实现这个要求的辅助手段。
ØC++中的友元为数据隐藏这堵不透明的墙开了一个小孔,外界可通过这个小孔窥视类内部的秘密,友元是一扇通向私有成员的后门。
Ø友元可分为:友元函数,友元成员,友元类。
Ø友元函数不是当前类的成员函数,而是独立于当前类的外部函数,但它可以访问该类的所有对象的成员,包括私有成员和公有成员。
Ø在类定义中声明友元函数时,需在其函数名前加上关键字friend。
此声明可以放在公有部分,也可以放在私有部分。
友元函数可以定义在类的内部,也可以定义在类的外部。
1.友元函数虽然可以访问类对象的私有成员,但它毕竟不是成员函数。
因此,在类的外部定义友元函数时,不必像成员函数那样,在函数名前加上“类名::”。
2.友元函数一般带有一个该类的入口参数。
因为友元函数不是类的成员,所以它不能直接引用对象成员的名称,也不能通过this指针引用对象的成员,它必须通过作为入口参数传递进来的对象名或对象指针来引用该对象的成员。
C++中各种数据成员及成员函数的定义及使⽤转载于:1.类是⾃定义的数据类型.类与应⽤程序不同,类的功能虽然独⽴,但不能独⽴启动,就象汽车零件那样.2.Class 是⼀种数据类型, 其变量为对象.对象包含有member variables(成员变量)和member1 functions(成员函数).2class Date{3int year, month, day;4public:5void set(int y,int m,int d); // 赋值操作6bool isLeapYear(); // 判断闰年7void print(); // 输出⽇期8 };3.在类(class)中 , 成员函数及成员变量会分为两⼤类 : public members (公开成员)、private members (私有成员)1.) public members :被定义为public members 的成员函数及成员变量 , 可在任何的函数中被使⽤ .包括main函数,及其它⾮成员函数.2.) private members :被定义为private members 的成员函数及成员变量 , 只能在成员函数中被使⽤ .4.成员函数在类外部定义时,在函数名称前应加上⽇期类名前缀Date和命名空间引导符“::”,它表⽰着⾃⼰属于某⼀个名空间(类),与普通函数相区别。
1void Date::set(int y,int m,int d) { year=y; month=m; day=d; }成员函数可以在类内,也可以在类外定义,若在类内定义,则默认为内联函数(inline)5.对象是拥有操作的实体,是由类创建的6.访问成员函数的⽅式(1)对象⽅式 Date d; d.set(2011,12,5);(2)对象指针⽅式1 Date* dp = new Date;2 dp->set(2011,12,5);3// …4delete dp;7.成员函数的操作,如果只对对象进⾏读操作,则该成员函数可以设计为常对象成员函数,好处是让使⽤者⼀⽬了然的知道该成员函数不会改变对象值,同时让类的实现者更⽅便地调试。
C++中成员函数和友元函数的使⽤及区别详解为什么使⽤成员函数和友元函数这个问题⾄关重要,直接影响着后⾯的理解:程序数据:数据是程序的信息,会受到程序函数的影响。
封装是⾯向对象编程中的把数据和操作数据的函数绑定在⼀起的⼀个概念,这样能避免受到外界的⼲扰和误⽤,从⽽确保了安全。
数据封装引申出了另⼀个重要的 OOP 概念,即数据隐藏。
数据封装是⼀种把数据和操作数据的函数捆绑在⼀起的机制,数据抽象是⼀种仅向⽤户暴露接⼝⽽把具体的实现细节隐藏起来的机制。
C++ 通过创建类来⽀持封装和数据隐藏(public、protected、private)。
我们已经知道,类包含私有成员(private)、保护成员(protected)和公有成员(public)成员。
默认情况下,在类中定义的所有项⽬都是私有的。
由于C++的封装和隐藏特性,只有类定义的成员函数可以访问类定义的私有数据。
成员函数是数据封装和数据隐藏的机制。
友元是C++提供的⼀种破坏数据封装和数据隐藏的机制。
成员函数的使⽤⾸先先看代码class Stock{ //class declarationprivate:std:: string company;long shares;double share_val;double total_val;void set_tot(){ total_val=shares* share_val;}public:void acquire(const std:: string & co, long n, double pr);void buy(long num, double price);void se11(long num, double price);void update(double price);void show();};//note semicolon at the end注意这⾥⾯的private可以不写,如果不写的话默认是私有的。
友元函数友元⽅式:1、全局函数友元(外部);2、成员函数友元;3、类友元。
特点:1、单向;友元不具有传递性、友元不具有继承性。
对象的成员有数据和⽅法,⼀般将数据设置为private或保护,由于类的封闭性和隐藏性;将⽅法设置为public。
只有通过对象调动⼀般⽅法来访问其私有成员。
this指针存在于⾮静态成员函数中,则静态成员函数没有this指针,对于静态成员函数既可以在类⾥声明,在类外定义,也可以在类⾥定义。
友元函数:要解决静态成员函数访问其私有成员,则以将static函数前加friend修饰符,变为友元函数。
友元函数既可以在类⾥声明,在类外定义,还可以在类⾥定义。
友元函数是在类定义中由关键字friend修饰的⾮成员函数。
友元函数不是本类的成员函数,则调⽤时不能通过对象调⽤,直接⽤函数调⽤。
静态成员函数在调⽤时既可以通过对象调⽤,还可以通过函数名直接调⽤。
友元关系:1、将⼀个⾮成员函数getval()声明为类Test的友元函数,使得该⾮成员函数可以访问类Test的私有成员。
1、截图如下:在类⾥声明友元函数,在类外定义2、在类⾥声明友元函数,并定义//先将⾮成员函数在类声明;注意class Test;应在其之前声明,避免编译出错结果:(两次的结果为)成员函数友元3、将⼀个类Test的某成员函数声明为Base类的友元函数,使得可以通过 Test类的这个成员函数访问类Base的私有成员注意:被屏蔽的代码为编译出错代码,原因是由于Test类中的void getnum(Base &it)的成员函数被未设置为Base类的成员函数友元,则之后访问Base类中的私有成员,则会访问失败。
在Tes类中不能在声明getval(Base &x)的时候进⾏定义,因为此时的Base类并未定义,只是在Test类之前进⾏了声明⽽已。
类友元(将Test类声明为Base类的友元类,使得可以通过类Test对象访问类的私有成员)格式为:class B{...friend class A;}结果为:注意:在Tes类中不能在声明getval(Base &x)的时候进⾏定义,因为此时的Base类并未定义,只是在Test类之前进⾏了声明⽽已。
C++友元函数和友元类(C++friend)详解私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接⼝(成员函数)间接地进⾏。
这固然能够带来数据隐藏的好处,利于将来程序的扩充,但也会增加程序书写的⿇烦。
是从结构化的C语⾔发展⽽来的,需要照顾结构化设计程序员的习惯,所以在对私有成员可访问范围的问题上不可限制太死。
C++ 设计者认为,如果有的程序员真的⾮常怕⿇烦,就是想在类的成员函数外部直接访问对象的私有成员,那还是做⼀点妥协以满⾜他们的愿望为好,这也算是眼前利益和长远利益的折中。
因此,C++ 就有了友元(friend)的概念。
打个⽐⽅,这相当于是说:朋友是值得信任的,所以可以对他们公开⼀些⾃⼰的隐私。
友元分为两种:友元函数和友元类。
友元函数在定义⼀个类的时候,可以把⼀些函数(包括全局函数和其他类的成员函数)声明为“友元”,这样那些函数就成为该类的友元函数,在友元函数内部就可以访问该类对象的私有成员了。
将全局函数声明为友元的写法如下:friend 返回值类型函数名(参数表);将其他类的成员函数声明为友元的写法如下:friend 返回值类型其他类的类名::成员函数名(参数表);但是,不能把其他类的私有成员函数声明为友元。
关于友元,看下⾯的程序⽰例。
1. #include<iostream>2. ug namespace std;3. class CCar; //提前声明CCar类,以便后⾯的CDriver类使⽤4. class CDriver5. {6. public:7. void ModifyCar(CCar* pCar); //改装汽车8. };9. class CCar10. {11. private:12. int price;13. friend int MostExpensiveCar(CCar cars[], int total); //声明友元14. friend void CDriver::ModifyCar(CCar* pCar); //声明友元15. };16. void CDriver::ModifyCar(CCar* pCar)17. {18. pCar->price += 1000; //汽车改装后价值增加19. }20. int MostExpensiveCar(CCar cars[], int total) //求最贵⽓车的价格21. {22. int tmpMax = -1;23. for (int i = 0; i<total; ++i)24. if (cars[i].price > tmpMax)25. tmpMax = cars[i].price;26. return tmpMax;27. }28. int main()29. {30. return 0;31. }这个程序只是为了展⽰友元的⽤法,所以 main 函数什么也不做。
C++中的friend友元函数(2011-03-2321:01:46)转载分类:C标签:friend友元教育友元函数是可以直接访问类的私有成员的非成员函数。
它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend。
我们已知道类具有封装和信息隐藏的特性。
只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。
非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性。
另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。
为了解决上述问题,提出一种使用友元的方案。
友元是一种定义在类外部的普通函数,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。
友元不是成员函数,但是它可以访问类中的私有成员。
友元的作用在于提高程序的运行效率(即减少了类型检查和安全性检查等都需要的时间开销),但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。
友元函数的特点是能够访问类中的私有成员的非成员函数。
友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样。
#include"cmath"#include"iostream"using namespace std;class Point{public:Point(double xx,double yy){x=xx;y=yy;}void GetXY();friend double Distance(Point&a,Point&b);protected:private:double x,y;};void Point::GetXY(){//cout<<"("<<this->x<<","<<this->y<<")"<<endl;cout<<"("<<x<<","<<y<<")"<<endl;}double Distance(Point&a,Point&b){double length;length=sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));//它可以引用类中的私有成员return length;}int main(void){Point p1(3.0,4.0),p2(6.0,8.0);p1.GetXY();//成员函数的调用方法,通过使用对象来调用p2.GetXY();double d=Distance(p1,p2);//友元函数的调用方法,同普通函数的调用一样,不要像成员函数那样调用cout<<d<<endl;system("pause");return0;}说明:在该程序中的Point类中说明了一个友元函数Distance(),它在说明时前边加friend 关键字,标识它不是成员函数,而是友元函数。
C++运算符重载三种形式(成员函数,友元函数,普通函数)详解三种重载⽅式⾸先,介绍三种重载⽅式:1//作为成员函数重载(常见)2class Person{3 Private:4string name;5int age;6public:7 Person(const char* name, int age):name(name),age(age){}8bool operator<(const Person& b);910 };11bool Person::operator<(const Person& b)12 {13//作为成员函数时,*this即为左操作数a14 ...15 }1//作为友元函数重载2class Person{3private:4string name;5int age;6public:7 Person(const char* name, int age):name(name),age(age){}8 friend bool operator<(const Person& a,const Person& b);910 };11bool operator<(const Person& a,const Person& b)12 {13 ...14 }1//作为普通函数重载(不推荐)2class Person{3public://注意,重载运算符为普通函数时,使⽤到的类成员必须为public4string name;5int age;6public:7 Person(const char* name, int age):name(name),age(age){}89 };10bool operator<(const Person& a,const Person& b)11 {12 ...13 }作为成员函数重载先介绍第⼀种:bool Person::operator<(const Person& b),bool是函数返回类型,Person::只是指定了成员函数所属类名。
类和对象初步1.类的定义在定义外成员函数的实现2.类的成员函数之间可以相互调用,类的成员函数也可以重载,也可设默认参数值3.一般来讲,一个对象占用的内存空间的大小等于其成员变量的体积之和。
每个对象都有自己的存储空间(成员变量),但成员函数只有一份对象名.成员名指针->成员名引用名.成员名4.private:一个类的私有成员,只能在该类的成员函数中才能访问public:proteced:5.class默认private struct默认public6.内联成员函数:成员函数名前加inline 或函数体写在类定义内部的成员函数。
执行更快,但会带来额外的内存开销构造函数1.构造函数全局变量在堆上,系统自动初始化为零。
局部变量在栈上,初始值是随机的,需要初始化。
2.构造函数:对对象进行初始化。
构造函数执行时对象的内存空间已经分配,构造函数的作用是初始化这片空间.可重载,不写的话有默认构造函数,但是如果编写了构造函数,那默认构造函数不会再执行.是一类特殊的成员函数。
不写返回值类型,函数名为类名.3.对象在生成时一定会调用某个构造函数,一旦生成,不再执行构造函数.4.P183 Ctest *pArray[3]={new Ctest(4),new Ctest(1,2)}5.复制构造函数:其是构造函数的一种,只有一个参数,为本类的引用,防止混淆,构造函数不能以本类的对象作为唯一的参数。
默认复制构造函数。
6.复制构造函数被调用的三种情形:1用一个对象去初始化另一个对象时Complex C1(C2)ComplexC2=C1; 2 函数的参数是类A的对象。
形参未必等于实参函数中用对象的引用不会调用复制构造函数void Function(const Complex &c)3 函数的返回值是类A的对象7.类型转换构造函数:除复制构造函数外,只有一个参数的构造函数C=68.析构函数:在对象消亡时调用,可以定义其做善后工作。