1.友元函数
定义类时,在类中加上关键字修饰函数,则该函数就能成为该类的友元函数,它可以访问该类的所有成员。关于友元函数需要注意以下几点:
(1)友元函数不是类的成员,不带this指针,必须通过对象名或者对象的引用作为友元函数的参数来访问对象的成员。友元函数必须在类定义中说明(但是对友元函数指定访问权限无效,因为友元函数不属于类,所以在类中不管哪声明都是一样的效果)可以在类外定义。
(2)友元函数的作用域跟一般的函数作用域一样。
(3)一个类可以定义若干个友元函数,也可以将任一个成员函数说明为另一个类的友元函数。
- class D;
- class C{
- ...
- public:
- void fun(D&);//此时只能声明函数,不能定义函数体,因为D还没定义
- };
- class D{
- ...
- friend void C::fun(D&);//声明友元函数
- };
-
- void C::fun(D&)//函数定义
- {......}
- class D;
- class C{
- ...
- public:
- void fun(D&);//此时只能声明函数,不能定义函数体,因为D还没定义
- };
- class D{
- ...
- friend void C::fun(D&);//声明友元函数
- };
-
- void C::fun(D&)//函数定义
- {......}
(4)可以将一个类设为另一个类的友元,这样另一个类能访问该类的所有成员。但是这种友元关系不能继承和传递。
- class C{
- ...
- public:
- void fun(D&);//此时只能声明函数,不能定义函数体,因为D还没定义
- };
- class D{
- ...
- friend void C::fun(D&);//声明友元函数
- };
- class C{
- ...
- public:
- void fun(D&);//此时只能声明函数,不能定义函数体,因为D还没定义
- };
- class D{
- ...
- friend void C::fun(D&);//声明友元函数
- };
2.虚函数
虚函数和重载技术实现了OOP的多态技术。
多态性有两种:(1)编译多态性:函数的重载和运算符的重载实现。函数的重载根据不同类型的实参或参数个数不同,在程序执行前就可确定应调用哪一个函数。运算符重载根据不同的运算对象在编译时就能确定执行一种运算。 (2)运行多态性:在程序执行前,根据函数名和参数无法确定调用哪个函数。必须在程序运行过程中动态绑定。
关于虚函数注意以下几点:
(1)一旦把某个类的成员函数定义为虚函数,该类的派生类中,该函数均保持虚函数的特性。当派生类中定义了一个与该虚函数同名的成员函数,并且参数个数、参数类型以及返回值类型都与基类中一样,则无论是否使用virtual关键字,它都成为一个虚函数。当函数名相同,而参数个数或者参数类型不同或者返回值类型不同时,属于函数重载而不是虚函数。
- #include<iostream>
-
- using namespace std;
- class A{
- public:
- virtual void print()
- {cout<<"A::print()"<<endl;}
- };
- class B:public A{
- public:
- virtual void print()
- {cout<<"B::print()"<<endl;}
- };
-
- int main()
- {
- A *pa;
- B b;
- A &pc = b;
- pa = &b;
- pa->print();
- pc.print();
- system("pause");
- return 0;
- }
- #include<iostream>
-
- using namespace std;
- class A{
- public:
- virtual void print()
- {cout<<"A::print()"<<endl;}
- };
- class B:public A{
- public:
- virtual void print()
- {cout<<"B::print()"<<endl;}
- };
-
- int main()
- {
- A *pa;
- B b;
- A &pc = b;
- pa = &b;
- pa->print();
- pc.print();
- system("pause");
- return 0;
- }
输出结果:
B:print()
B:print()
(2)实现这多态性必须有基类的指针或引用指向子类对象,并通过指针或引用调用虚函数,如上面这个例子。
(3)虚函数必须是类的成员函数,不能是静态成员函数,也不能是友元函数。可以把析构函数说明为虚函数,但是构造函数不能。
(4)虚函数与一般的函数相比调用的速度要慢一些,慎用。
- #include<iostream>
-
- using namespace std;
- class A{
- public:
- A(){fun();}
- virtual void fun()
- {cout<<"A::fun()"<<endl;}
- };
-
- class B:public A{
- public:
- B(){fun();}
- virtual void fun()
- {cout<<"B::fun()"<<endl;}
- void g(){fun();}
- };
-
- class C:public B{
- public:
- C(){fun();}
- virtual void fun()
- {cout<<"C::fun()"<<endl;}
- };
- int main()
- {
- C c;//这里注意的是首先调用基类的构造函数 //F
- c.g();
- system("pause");
- return 0;
- }
- #include<iostream>
-
- using namespace std;
- class A{
- public:
- A(){fun();}
- virtual void fun()
- {cout<<"A::fun()"<<endl;}
- };
-
- class B:public A{
- public:
- B(){fun();}
- virtual void fun()
- {cout<<"B::fun()"<<endl;}
- void g(){fun();}
- };
-
- class C:public B{
- public:
- C(){fun();}
- virtual void fun()
- {cout<<"C::fun()"<<endl;}
- };
- int main()
- {
- C c;//这里注意的是首先调用基类的构造函数 //F
- c.g();
- system("pause");
- return 0;
- }
运行结果:
这里要注意:F行首先调用基类的构造函数,在构造函数中调用虚函数时,只调用自己类中定义的函数(若类中没有定义,则调用基类的构造函数),所以有上面的结果,而不是C:fun(),C:fun(),C:fun(),C:fun()。
3.纯虚函数
在以抽象类作为基类的派生类中,必须有纯虚函数的实现部分。否则,这样的类也不能产生对象。抽象类的唯一用途是为派生类提供基类。纯虚函数作为派生类中的成员函数的基础,并实现多态性。
4.const、volatile对象
const、volatile可以修饰成员函数和对象。const修饰的对象只能访问const修饰的成员函数,不能访问其他成员函数。volatile修饰的对象只能访问volatile修饰的成员函数,不能访问其他成员函数。
当希望成员函数只能引用成员数据的值,而不能修改成员数据的值时,可以将成员函数定义为const成员函数(const加在后面才表示const成员函数,加在前面表示返回值为const)。
volatile修饰的成员函数具有一个易变的this指针。调用该函数时,编译程序把属于此类的所有成员数据看作易变的变量,编译器不要对成员函数做优化工作。
const和volatile可以同时修饰一个函数。
- #include<iostream>
-
- using namespace std;
- class A{
- int i,j;
- public:
- A(int a=0,int b=0)
- {
- i=a;j=b;
- }
- int getI()const{return i;}
- void show()volatile{cout<<"show"<<endl;}
- };
-
-
- int main()
- {
- A a(100,200);
- const A a1(50,60);
- volatile A a2(200,300);
- a.show();//a可以调用任何无限制
- cout<<"i="<<a1.getI()<<endl;//a1只能调用const函数
- a2.show();//a2只能调用volatile函数
- system("pause");
- return 0;
- }
- #include<iostream>
-
- using namespace std;
- class A{
- int i,j;
- public:
- A(int a=0,int b=0)
- {
- i=a;j=b;
- }
- int getI()const{return i;}
- void show()volatile{cout<<"show"<<endl;}
- };
-
-
- int main()
- {
- A a(100,200);
- const A a1(50,60);
- volatile A a2(200,300);
- a.show();//a可以调用任何无限制
- cout<<"i="<<a1.getI()<<endl;//a1只能调用const函数
- a2.show();//a2只能调用volatile函数
- system("pause");
- return 0;
- }
|