c++封装、继承和多态

封装(encapsulation)封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过 外部接口,一特定的访问权限来使用类的成员。通过封装使一部分成员充当类与外部的接口,而将其他的成员隐蔽起来,这样就达到了对成员访问权限的合理控制,使不同类之间的相互影响减少到最低限度,进而增强数据的安全性和简化程序的编写工作。


继承:继承是面向对象软件技术当中的一个概念。如果一个类B继承自另一个类A,就把这个B称为A的子类,而把A称为B的父类。继承可以使得子类具有父类的各种属性和方法,而不需要再次编写相同的代码。在令子类继承父类的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类的原有属性和方法,使其获得与父类不同的功能。


多态(Polymorphisn):多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说:允许将子类类型的指针赋值给父类类型的指针。多态性在C++中都是通过虚函数(Virtual Function)实现的。虚函数就是允许被其子类重新定义的成员函数。而子类重新定义父类虚函数的做法,称为“覆盖”或者称为“重写”(override)。



接下来以示例进行讲解:

继承:

class BaseClass{
public:
    int a;
    void test1();
    virtual void printFunc(){
    cout<<"This is BaseClass."<<endl;
    }
protected:
    int b;
    void test2();
private:
    int c;
};
class DerivedClassA : public BaseClass{
public:
    void printFunc(){
    cout<<"This is DerivedClassA."<<endl;
    }
    void testA(){
       cout<<a<<endl
       <<b<<endl
       <<c<<endl;//报错
    }
private:
    int d;
};

访问控制和继承权限

访问控制:

在基类中,public和private标号具有普通含义:用户代码可以访问类的public成员而不能访问private成员,private成员只能由基类的成员和友元访问。派生类对基类的public和private成员的访问权限与程序中任意其他部分一样:它可以访问public成员而不能访问private成员。有时作为基类的类具有一些成员,它希望允许派生类访问但仍禁止其他用户访问这些成员。对于这样的成员应使用受保护的访问标号。protected成员可以被派生类对象访问但不能被该类型的普通用户访问。

继承权限:

公用继承:基类成员保持自己的访问级别,基类的public成员为派生类的 public成员,基类的protected成员为派生类的protected成员。

受保护继承:基类的public和protected成员在派生类中为protected成员。

私有继承:基类的的所有成员在派生类中为private成员。


上述例子中,在派生类中使用基类的数据成员a和b都没有问题,但是使用c就会报错。


多态:

C++ 中的函数调用默认不使用动态绑定。要触发动态绑定,满足两个条件:第一,只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不进行动态绑定;第二,必须通过基类类型的引用或指针进行函数调用。要理解这一要求,需要理解在使用继承层次中某一类型的对象的引用或指针时会发生什么。

派生类中对于虚函数的重新定义不需要加virtual关键字,只要基类中有就行。

现在再定义一个派生类:

class DerivedClassB : public BaseClass{
public :
    void printFunc(){
    cout<<"This is DerivedClassB."<<endl;
    }
};


测试示例:

void main() {
    BaseClass *b1,*b2,*b3;
    BaseClass bc;
    DerivedClassA dcA;
    DerivedClassB dcB;
    b1 = &bc;
    b2 = &dcA;
    b3 = &dcB;
    b1->printFunc(); //调用基类的方法
    b2->printFunc();  //调用派生类A的方法
    b3->printFunc();  //调用派生类B的方法
}


友元关系与继承:


友元可以访问类的 private和protected数据。友元关系不能继承。基类的友元对派生类的成员没有特殊访问权限。如果基类被授予友元关系,则只有基类具有特殊访问权限,该基类的派生类不能访问授予友元关系的类。


class Base {
friend class Frnd;
protected:
int i;
};
class D1 : public Base {
protected:
int j;
};
class Frnd {
public:
int mem(Base b) { return b.i; }
int mem(D1 d) { return d.i; } // 报错
inherit
};
class D2 : public Frnd {
public:
int mem(Base b) { return b.i; } // 报错
inherit
};


屏蔽与重载

如果派生类重定义了重载成员,则通过派生类型只能访问派生类中重定义的那些成员。

如果派生类想通过自身类型使用的重载版本,则派生类必须要么重定义所有重载版本,要么一个也不重定义。

有时类需要仅仅重定义一个重载集中某些版本的行为,并且想要继承其他版本的含义,在这种情况下,为了重定义需要特化的某个版本而不得不重定义每一个基类版本,可能会令人厌烦。

派生类不用重定义所继承的每一个基类版本,它可以为重载成员提供 using

声明。一个 using 声明只能指定一个名字,不能指定形参表,因此,为基类成员函数名称而作的 using 声明将该函数的所有重载实例加到派生类的作用域。将所有名字加入作用域之后,派生类只需要重定义本类型确实必须定义的那些函数,对其他版本可以使用继承的定义。

class BaseClass{
public:
    void test1(){
        cout<<"BaseTest1"<<endl;
    }
    virtual void printFunc(){
    cout<<"This is BaseClass."<<endl;
    }
private:
    int a;
};
class DerivedClassA : public BaseClass{
public:
    void printFunc(){
    cout<<"This is DerivedClassA."<<endl;
    }
    void test1(int t){
    cout<<"DerivedClassATest1"<<endl;
    }
private:
    int b;
};
void main() {
    BaseClass bc;
    DerivedClassA dcA;
    bc.test1();
    dcA.test1(1);
    dcA.test1();  //报错,被屏蔽了
    dcA.BaseClass::test1();
}

   通过多态,可实现基类调用被屏蔽的虚函数。使用基类的指针来指向派生类的对象。





你可能感兴趣的:(C++,继承,多态,封装)