第20章:Derived Classes

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! 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值