继承的几个测试

来源:互联网 发布:tenga 根沐 知乎 编辑:程序博客网 时间:2024/06/05 16:58

c++好多年不学了。

突然捡起来,非常的不适应,不仅仅是头疼,而是当年学的粗浅,任何概念都不深入。只好测一测。


===========

静态的成员函数,可以被子类覆盖么?

我也不知道这算不算覆盖。

#include <iostream>using namespace std;class   base   {public:    static int statFun(){cout << "in class base"<<endl;}    //......};class   derived1:public   base{    //......};class   derived2:public   base{public:    static int statFun(){cout << "in class derived2"<<endl;}    //......};int main(int argc, char *argv[]){    base::statFun(); //父类自身的     derived1::statFun(); //父类的     derived2::base::statFun(); //父类的    derived2::statFun(); //自身的         system("pause");     return 0;}


可以看到子类1继承了父类的静态函数。

子类2覆盖了父类的静态函数,用 的自己的。

所以说,静态函数可以被子类继承,也可以被子类覆盖。


=======================================

参考http://blog.csdn.net/taina2008/article/details/1684834


这是一个多继承的例子。


#include<iostream>using namespace std;class Employee {//职工 public:    void skill()//职工技能    {        cout<<"我的skill水平就是Employee"<<endl;    }}; class Technical: public Employee {//技术,也是职工 }; class Manager: public Employee {//经理,也是职工 }; class TechnicalManager:public Technical,public Manager {//技术经理,也是职工 }; int main(int argc, const char * argv[]){    TechnicalManager tManager;    /*    28 E:\codeReocrdi\test.cpp request for member `skill' is ambiguous      error E:\codeReocrdi\test.cpp:8 candidates are: void Employee::skill()      8 E:\codeReocrdi\test.cpp                 void Employee::skill()     */     //tManager.skill();//此处编译错误    tManager.Technical::skill();    tManager.Manager::skill();    system("pause");    return 0;} 
可以看到多继承下的子类,会在内存中有两份父类的方法的拷贝,编译器不知道该选择啥了。

但是如果指定了其某个父类的方法,就可以顺利输出了。





===========================================================


继承的时候,先调用父类的构造函数,然后是子类的构造函数。


#include <iostream.h>  using namespace std;class animal  {   public:       animal(int height, int weight)       {          cout<<"animal construct"<<endl;       }  };  class fish:public animal  {     public:        fish():animal(400,300)        {              cout<<"fish construct"<<endl;        }};  int main()  {     fish fh;     system("pause");   return 0;}  





而且如果有带有参赛的构造函数,必须在构造函数中用:父类名(初始值)方式显示初始化父类构造函数。

比如MediaSource的构造函数,显示调用了父类Medium的有参数构造函数:



参考http://blog.csdn.net/hemmingway/article/details/7853713

构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承(子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法)。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。

如果没有显式的构造函数,编译器会给一个默认的构造函数,并且该默认的构造函数仅仅在没有显式地声明构造函数情况下创建。


有个原则,参考http://blog.csdn.net/hemmingway/article/details/7853713

    1. 如果子类没有定义构造方法,则调用父类的无参数的构造方法。

    2. 如果子类定义了构造方法,不论是无参数还是带参数,在创建子类的对象的时候,首先执行父类无参数的构造方法,然后执行自己的构造方法。

    3. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数,则会调用父类的默认无参构造函数。

    4. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类自己提供了无参构造函数,则会调用父类自己的无参构造函数。

    5. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类只定义了自己的有参构造函数,则会出错(如果父类只有有参数的构造方法,则子类必须显示调用此带参构造方法)。

    6. 如果子类调用父类带参数的构造方法,需要用初始化父类成员对象的方式




============================================================

 父类   temp * =new 子类();
temp.某函数();
子类   temp * =new 子类();
temp.某函数(); 

关于虚函数的继承

虚函数这里会牵扯到一个“多态”的概念。我也很糊涂了。因为还有个“虚拟继承”,区别于这里的“虚函数继承”
虚函数继承就是覆盖。即基类中的虚函数被派生类中的同名函数所覆盖。
虚函数继承是可以覆盖父类的同名函数的。但是声明为virtual的虚函数还有一个特点就是当父类的对象指针去指向子类对象时,会有“多态”发生。
如下:

#include <iostream>  using namespace std;//虚函数继承: class A {       public:      virtual void fun() {cout <<'A' <<endl;}; }; class B : public A {       public:       virtual void fun() {cout <<'B' <<endl;}; }; int main(int argv, char** argc) {     A *a=new A;    a->fun(); //A     A* p = new B;     p->fun(); //结果输出B,而不是A,至于实现原理,其实是对象头部多了四个字节,它是一个指向虚函数表的地址指针,程序运行时通过这个表,找到了这个B::fun()的入口地址     B* b=new B;    b->fun();  //B     system("pause");    return 0; }

参考http://alice-2860.blog.163.com/blog/static/490180162009975245293/


虚继承是为了在多继承的时候避免引发歧义, 
比如类A有个就是a,B继承了A,C也继承了A,当D多继承B,C时,就会有歧义产生了,所以要使用虚拟继承避免重复拷贝。 
虚函数继承是解决多态性的,当用基类指针指向派生类对象的时候,基类指针调用虚函数的时候会自动调用派生类的虚函数,这就是多态性,也叫动态编联




下面的这个例子里,父类有一个虚函数,子类没有虚函数,但是子类有一个和父类的这个虚函数同名的函数。

父类的指针指向子类对象时,声明为virtual的父类虚函数1不会执行,执行的是是子类同名的非virtual函数1。
而父类非virtual的函数2会执行,不执行子类非virtual的函数2.

如下:


#include <iostream>  using namespace std;//虚函数继承:class parent {   public:   virtual void foo(){cout <<"foo from parent"<<endl;};   void foo1(){cout <<"foo1 from parent";}; }; class son:public parent {   void foo(){cout <<"foo from son"<<endl;};   void foo1(){cout <<"foo1 from son"<<endl;}; }; int main() {   parent *p=new son();   p->foo(); //son   p->foo1();//parent   system("pause"); return 0; } 


难道是可以这么认为:

只有父类virtual的函数,才会有多态发生在子类上?



多态:


参考

http://blog.csdn.net/bao_jinyu/article/details/7843275

1.1 多态 
    在了解了虚函数的意思之后,再考虑什么是多态就很容易了。仍然针对上面的类层次,但是使用的方法变的复杂了一些:

foo()是类A的虚函数,那么:

void bar(A * a)
{
    a->foo();  // 被调用的是A::foo() 还是B::foo()?
}

因为foo()是个虚函数,所以在bar这个函数中,只根据这段代码,无从确定这里被调用的是A::foo()还是B::foo(),但是可以肯定的说:如果a指向的是A类的实例,则A::foo()被调用,如果a指向的是B类的实例,则B::foo()被调用。


===========================

再加一个,可以得到这样的结论:

对于父类的virtual,如果去掉virtual就跟普通的函数一样,加了virtual就可以用多态机制。


 如果子类没重写这个函数,就用父类的实现
如果子类重写了,则只用子类的实现

#include <iostream>  using namespace std;//虚函数继承:class parent {   public:   virtual void foo(){cout <<"foo from parent"<<endl;};   void foo1(){cout <<"foo1 from parent"<<endl;}; }; class son:public parent {       public:  void foo(){cout <<"foo from son"<<endl;};   void foo1(){cout <<"foo1 from son"<<endl;}; }; int main() {   parent *p=new son();   p->foo(); //son   p->foo1();//parent       son *s=new son;  s->foo(); //son  s->foo1();//son     system("pause"); return 0; } 

子类完全可以无视父类的virtual


======================================================