20.4: Abstract Classes
1: 先看如下代码例子:
struct shape
{
virtual void rotate(int)=0;
virtual void draw() const=0;
~shape();
};
在上述代码中,shape中的成员函数rotate(int)和draw()被称作是纯虚函数。纯虚函数不仅有virtual声明,还有’=0’的伪初始化。
2: 一个类能否被称作抽象类就看这个类是否包含了纯虚函数,如果包含了就称为抽象类。抽象类不能定义对象,像shape s
这样的语句是错误的,因为shape是抽象类。一般来说,抽象类为其派生类提供了接口继承,但不提供实现继承。
20.5:Access Control
1:一个类的成员可能是public,也有可能是protected,也有可能是private;
(1):如果这个类成员属于public,那么这个类成员可以被任何函数使用;
(2):如果这个类成员属于protected,那么这个类成员仅仅可以被这个类的成员函数,友元以及该类的成员函数及友元调用;
(3):如果这个类成员属于private,那么这个类成员仅仅可以被这个类的成员函数及友元调用。
2:如果设计一个类时,我们想要在这个类中定义一些函数,这些函数能够被其派生类调用,但不想这些函数被普通用户使用,我们可以把这些函数设计为protected成员。一般来说,我们最好不要声明数据成员为protected,因为这些数据成员在派生类中是可见的,如果在派生类也定义了一个相同名字的变量,这就会增加编译错误出现的概率。 我们最好把数据成员声明为private,不仅有利于类的封装性还可以减少编译错误出现的概率
3:派生类继承基类有三种继承方式,即public继承,protected继承,private继承,示例如下:
class A:public B{};
class A:protected B{};
class A:private B{};
这三种继承方式决定了基类成员在派生类中的访问级别
1. 如果是public继承,则基类的public成员为派生类的public成员,基类的protected成员为派生类的protected成员;
2. 如果是protected继承,则基类的public和protected成员在派生类中为protected成员;
3. 如果是 private继承,则基类的所有成员在派生类中为private成员。
注意:这些继承方式影响着派生类到基类的指针及引用转换。
假设A是基类,B是派生类;
1. 如果是private继承,则仅仅在B的友元和成员函数中可以把B*转换成A*;
2. 如果是protected继承,则仅仅在B的友元和成员函数以及B派生类的友元和成员函数中可以把B*转换成A*;
3. 如果是public继承,则在任何函数中可以把B*转换成A*。
虽然看起来很复杂,但可以总结出一点规律:在基类Apublic成员可以被访问的地方均可以把B*转换成A*。
20.6
1:指向类中非静态成员函数和非静态数据成员的指针表示:
看下面的例子应该就明白了
struct C{
const char* val;
int i;
void print(int x){cout<<val<<x<<endl;}
int f1(int);
void f2();
C(const char* v){val=v;}
};
using Pmfi=void(C::*)(int);
using Pm=const char* C::*
void f(C&z1,C& z2)
{
C* p=&z2;
Pmfi pf=&C::print; //pf为指向C::print()成员函数的指针
Pm pm=&C::val; // pm为指向C::val数据成员的指针
z1.print(1);
(z1.*pf)(2); //类对象通过指向成员函数的指针调用成员函数
z1.*pm="nv1"; //类对象通过指向数据成员的指针调用其数据成员
p->*pm="nv2"; //类对象指针通过指向数据成员的指针调用其数据成员
z2.print(3);
(p->*pf)(4); //类对象指针通过指向成员函数的指针调用成员函数
pf=&C::f1; //error! return type mismatch;
pf=&C::f2; //error! argument type mismatch;
pm=&C::i; //error! type mismatch;
pm=f; //error! type mismatch;
}
2:指向类中静态成员函数的指针
在前面给出指向类中非静态成员函数和非静态数据成员指针的时候,我们都给出了类的作用域。但对于类中静态成员函数和数据成员来说,则不需要。代码例子如下:
class C{
static void f();
};
void (*p)()=&C::f; //Okay!
void (C::*p)()=&C::f; //error!
3:基类和派生类中非成员函数和非数据成员的指针表示:
派生类中至少拥有从基类中继承的成员,经常或许有更多的成员。因此,我们可以把指向基类成员的指针赋值给指向派生类成员的指针,反之则不可以,因为派生类中的成员在基类中不一定存在;
代码例子如下:
class A{
public:
virtual int f();
};
class B:public A{
public:
virtual int g();
}
int(B::*p1)()=&A::f; //okay!
int(A::*p2)()=&B::g; //error!