一、C++继承

(1)继承方式

public公有继承

protected保护继承

private私有继承

继承真正的意义在于派生类有基类的所有部分,包括派生类的private成员变量,只不过在派生类的成员函数都不可以访问,只能通过派生类的构造函数,调用基类的构造函数进行构造,这也就是构造函数的意义所在。

每个类维护自己的接口。

protected和public成员,派生类中成员可以访问。

虚函数继承会默认成为虚函数,即使不写virtual。

虚函数应用的是动态绑定,动态类型是哪个,就调用哪个的虚函数。

public继承是is a的关系,继承类对象是一种基类对象,只要用基类的对象都可以用继承类对象替代,这是面向对象的一个思想。

 

以下是从别人博客中摘取:

我们知道类的private和protected成员,在类外是不可以使用的.只有public成员可以在类外直接使用.

公有继承时,基类的private成员派生类也不可用,基类的public和protected成员在派生类中可直接使用.继承过来(变成派生类相应的public和protected成员)只有public成员在派生类外可以直接使用.

保护继承时,基类的private成员仍为有私有.基类的public和protected成员变成派生类的protected成员,这时在派生类外也不能直接使用原基类的public成员

私有继承时,基类的private成员仍为有私有.基类的public和protected成员将变成派生类的private成员.

 

举个例子.

class A

{

 public:             int m_nTelNum;

protected:        int m_nAge;

private:           int m_nMoney;

};

 

class B : public A   //其实相当于B有A的一个副本,public :int m_nTelNum;protected: in m_nAge;注意 private没有继承过来

{

void SetTelNum(int nTelNum)

            { m_nTelNum=nTelNum; }

void SetAge(int nAge)

            { m_nAge=nAge; }

void SetMoney(int nMoney)

            { m_nMoney=nMoney; }

//这里就出现错误,因为基类的private成员不能用,没有继承过来,是基类私有的,对继承类不可见

};

 

B objB;                 //创建B类的对象objB

objB.m_nTelNum=123456;//可以

objB.m_nAge=30;       //错误,因为public继承中基类的protected在派生类中是protected

objB.m_nMoney=100;   //更错误,在派生类中都不可以直接使用.在类外就更不能了.

 

class C : protected A   //能继承的全变成protected

{

void SetTelNum(int nTelNum)

{ m_nTelNum=nTelNum; }

void SetAge(int nAge)

{ m_nAge=nAge; }

void SetMoney(int nMoney)

{ m_nMoney=nMoney; }

//这里就出现错误,因为这是基类的private成员不能用.

};

C objC;//创建C类的对象objC

objC.m_nTelNum=123456;//注意这里和public的区别,这里错误,m_nTelNum变成了C类的protected成员

objC.m_nAge=30;//错误.protected继承中基类的protected在派生类中是protected,这与public同相

objC.m_nMoney=100;//更错误,在派生类中都不可以直接使用.在类外就更不能了.

 

class D : private A   //能继承的全变成private

{

void SetTelNum(int nTelNum)

{ m_nTelNum=nTelNum; }

void SetAge(int nAge)

{ m_nAge=nAge; }

void SetMoney(int nMoney)

{ m_nMoney=nMoney;

//这里就出现错误,因为这是基类的private成员不能用.

} };

 

D objD;//创建D类的对象

objD objD.m_nTelNum=123456;//错误,m_nTelNum变成了D类的private成员

objD.m_nAge=30;//错误.private继承中基类的protected在派生类中是private

objD.m_nMoney=100;//更错误,在派生类中都不可以直接使用.在类外就更不能了.

 

 

从例子来看,三种继承从派生类内部引用来看好像没有区别,只在类外引用时表现不同.现在还看不出public和protected继承的区别 那再看一个例子.

class E:public B

{

void SetTelNum(int nTelNum)

{ m_nTelNum=nTelNum;//可以 因为这是B的公有成员 }

void SetAge(int nAge)

{ m_nAge=nAge;//可以 因为这是B的保护成员,现成变成E的protected成员 }

 void SetMoney(int nMoney) { m_nMoney=nMoney;//这个肯定不可以! } };

 

E objE;

objE.m_nTelNum=123456;//可以

//其它的两个就不能用了.

 

class F:public C

{ void SetTelNum(int nTelNum)

{ m_nTelNum=nTelNum;//可以 因为这是C的保护成员,这里与public继承已经有区别但还没有表现出来 }

void SetAge(int nAge) {

m_nAge=nAge;//可以 因为这是C的保护成员,现成变成E的protected成员 }

void SetMoney(int nMoney)

{ m_nMoney=nMoney;//这个肯定不可以! } };

F objF;

objF.m_nTel=123456;//错误,因为这是F的保护成员.注意与E类区别

 

class G : public D

{

void SetTelNum(int nTelNum)

{ m_nTelNum=nTelNum;//不可以 因为这是D的private成员,注意这里区别 }

void SetAge(int nAge)

{ m_nAge=nAge;//不可以 因为这是D的private成员,注意区别 }

void SetMoney(int nMoney)  

 

     上表是对该文档的总结,即基类中的private在任何情况下子类及子类外均不可用,虽然子类继承了它。其他成员按相应继承方式转化为相应类型的成员,并在子类内可以访问,在子类外是否可用主要取决于继承后成员属性的访问说明符,这和正常的类成员一样。

 

protected和private的区别:

protected   与private只有在继承是才起到作用.

 

protect   和privete   主要是描述定义类成员的时候用到,主要作用是对该类的派生类成员调用该类成员的权限问题`````

 

protect的成员只有派生类和自己能访问。
也就是说,这种成员,对于派生类,相当于public,而对于外部,相当于private。

c++里面的protect和public、private有什么区别?

public修饰的成员变量 在程序的任何地方都可以被访问,就是公共变量的意思,不需要通过成员函数就可以由类的实例直接访问

 

private修饰的成员变量 只有类内可直接访问,私有的,类的实例要通过成员函数才可以访问,这个可以起到信息隐藏

 

protected是受保护变量 类内和子类可直接访问,也就是说,基类中有protected成员,子类继承于基类,那么也可以访问基类的protected成员,要是基类是private成员,则对于子类也是隐藏的,不可访问

 

(2)public,protected,private补充

private:  私有控制符。这类成员只能被本类中的成员函数和类的友元函数访问。 

protected:  受保护控制符。这类成员可以被本类中的成员函数和类的友元函数访问,也可以被派生类的成员函数和类的友元函数访问。

public:  共有控制符。这类成员可以被本类中的成员函数和类的友元函数访问,也可以被类作用域内的其他函数引用。 

virtual:  

C++通过虚函数实现多态."无论发送消息的对象属于什么类,它们均发送具有同一形式的消息,对消息的处理方式可能随接手消息的对象而变"的处理方式被称为多态性。而虚函数是通过Virtual关键字来限定的。  

只 要是学过C++的人都知道在类Base中加了Virtual关键字的函数就是虚拟函数(例如函数print),于是在Base的派生类Derived中就 可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。当基类Base的指针point指向派生类Derived的对象时,对point的print函数的调 用实际上是调用了Derived的print函数而不是Base的print函数。这是面向对象中的多态性的体现。  

虚函数是在类中被声明为virtual的成员函数,当编译器看到通过指针或引用调用此类函数时,对其执行晚绑定。 (动态绑定)

  

1.  

public / protected / private / virtual  

c++中,成员默认为private访问权限。  

structure中,成员默认为public访问权限。  

二者都支持继承/构造/析构等。  

对象是类的实例化。成员函数对于整个类而言却是被所有的实例化的类对象共享的,即一个类只保留一份成员函数。 每一个实例对象都只是对其中的数据成员初始化,内存映像中每个对象仅仅保留属于自己的那份数据成员副本。  

那么每个对象怎样和这些可以认为是“分离”的成员函数发生联系,即成员函数如何操作对象的数据成员?记住this指针,无论对象通过(.)操作或者(->)操作调用成员函数,编译时刻,编译器都会将这种调用转换成我们常见的全局函数的形式,并且多出一个参数(一般这个参数放在第一个),然后将this指针传入这个参数。于是就完成了对象与成员函数的绑定(或联系)。  

类的定义使用到三种访问修饰符private/public/protected,它们要控制的是一个函数对一个类的成员(包括成员变量及成员方法)的访问权限。  

private: 只能由该类中的函数、其友元函数访问,除此之外的用户程序都不能通过类对象对其进行访问;  

protected: 可以被该类中的函数、子类的函数(public继承下)、以及其友元函数访问,除此之外的用户程序都不能通过类对象对其进行访问;  

public: 可以被该类中的函数、子类的函数(public继承下)、其友元函数访问,在用户程序中也可以由该类的对象对其进行访问。  

总结起来就是:  

    一个类友元(包含友元函数或者友元类的所有成员函数)可以访问该类的任何成员(包括成员变量及成员方法)。  

    除去友元外,private成员只有该类自身的成员函数可以访问,protected成员只有该类的成员函数及其派生类的成员函数可以访问,public成员则所有的函数都可以访问。  

类的成员,不管使用哪种访问修饰符,都必须通过类的对象进行访问。即使是在类的成员函数内部,访问的数据也是通过类对象进行的,每个成员函数默认的第一个形参为this指针,其中访问的数据成员全部是由“this->”这种方式进行的,只是默认情况下都省略了而已。C++的访问修饰符的作用是以类为单位,而不是以对象为单位。通俗的讲,同类的对象间可以“互相访问”对方的数据成员,只不过访问途径不是直接访问。  

2. 类继承后成员访问属性变化:  

使用private继承,父类的所有成员在子类中变为private;  

使用protected继承,父类的protected和public成员在子类中变为protected,private成员不变;  

使用public继承,父类中的方法属性不发生改变。  

经过类的继承以后,基类的成员可以理解为:成为了继承类的成员,只是要做相应的访问属性改变,虽然基类成员好像是成为了继承类成员,但是还是和本身继承类数 据成员有区别的,例如:继承类成员函数是不能访问继承过来的基类的私有成员,但可以访问继承过来的公有和保护成员。  

3. virtual保留字  

这 里我们要讲的多态是指生效于运行时的动态多态,C++的动态多态技术是基于继承机制和虚函数的。多态可以理解成:不同的动作行为可以与同一个记号相关联。 通俗的讲:基类类型的指针或引用可以调用基类的函数,也可以执行继承类的函数。这里的函数调用必须有个动态绑定,要实现这种动态绑定必须满足两个条 件:  

    只有指定为虚函数的成员函数才能进行动态绑定;  

    必须通过基类类型的指针或者引用进行函数调用。  

 

引 用和指针的静态类型和动态类型可以不同,这是C++用以支持多态性的基石。因为每个派生类对象都包含基类部分,所以可以用基类类型的引用绑定到派生类对象 的基类部分,也可以用基类类型的指针指向派生类对象(但是不能用继承类类型引用或指针绑定基类对象,除非强制类型转换)。基类类型的引用或者指针在编译就 是可知的,这是静态类型,但是的它们所绑定的对象类型在运行时才可知,而且可能与的它们的静态类型不同,所以它们最终绑定的类型就是动态类型。 

 

要理解多态中的动态绑定,首先要理解C++如何在继承层次中确定函数调用:  

    首先确定进行函数调用的对象、引用或指针的静态类型;  

    在该类中查找和调用的函数名字相同(不管参数)的函数,如果找不到,就在该类的直接基类中查找,如此循着它继承链往上找,直到找到名字相同的函数或者找完最后一个类,如果不能在类或者其他基类中找到该名字,则调用是错误的;  

    一旦在某个类中找到一个和待调用的函数名字相同的函数,则在这个类中查找所有这个名字的函数重载版本,看能否找到一个能与待调用函数实参类型相同的函数,不能找到则调用不合法;(前三个步骤是在编译的时候确定)  

    如果函数调用合法,如果函数是虚函数,且通用引用或者指针调用,则编译器生成代码以确定根据对象的动态类型运行哪个函数版本,否则编译器生成代码直接调用函数。  

单 纯从virtual关键字出发,考虑两层关系:一个基类一个继承类,使用基类类型引用或者指针进行函数调用,首先在基类中查找一个能与待调用函数实参类型 相同的函数,如果找不到,则调用出错;如果找到,看该函数是否是虚函数,如果基类中该函数是虚函数,而且继承类中有相同原型的函数,即使没有用 virtual保留字,继承类中的函数自动变成虚函数,然后再运行过程中根据基类指针或引用绑定的对象来调用相应的函数,如果继承类中没有相同原型的函 数,即使运行时绑定的是继承类对象,那么还是调用基类中的函数。

 

 posted on 2014-05-05 23:00  zmlctt  阅读(629)  评论(0编辑  收藏  举报