二义性、虚函数、纯虚函数、虚基类、抽象类、基类对象与派生类对象之间赋值兼容原则

来源:互联网 发布:谱谱风打谱软件 编辑:程序博客网 时间:2024/06/06 17:08

一、二义性问题
1.在多继承时,基类与派生类之间,或基类之间出现同名成员时,将出现访问二义性,采用虚函数或同名覆盖原则来解决;若要通过派生类的对象访问基类中被同名覆盖的同名成员,应使用基类名限定 。
2.当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生二义性,采用虚基类来解决。
二、虚函数
1.虚函数虚就虚在“推迟联编”或者动态联编上。一个类函数的调用并不是在编译时刻就被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是某个派生类的函数,所以称为“虚”函数。虚函数只是借助于指针或者引用来实现多态的的效果。
2.#include<iostream>
using namespace std;
class A{
public:
   virtual void fun(){
  cout<<"A::fun()!"<<endl;
 }
};
class B:public A{
public:
 virtual void fun(){
  cout<<"B::fun()!"<<endl;
 }
 };
int main(){
 A *a=new B();
 a->fun();
 return 0;
}
//输出结果为B::fun()!
//如果把virtual都去掉,则输出结果为A::fun()!
//如果只把B中的virtual都去掉,则输出结果为B::fun()!
//如果只把A中的virtual都去掉,则输出结果为A::fun()!
3.c++支持两种多态:
(1)编译时多态:通过重载函数来实现;
(2)运行时多态:通过虚函数来实现。
三、纯虚函数
 1. 定义:
 class <类名>   {  
 virtual <类型><函数名>(<参数表>)=0;  
 …  
 };
2.作用:
在有些情况下,因为基类本身生成对象是不合情理的,所以在基类中不能对虚函数给出有意义有实现,而把它说明为纯虚函数,它的实现留给该基类的派生类去做。
四、虚基类
1.虚基类:用于有共同基类的场合,在第一级继承时就要将共同基类设计为虚基类(也就是说在继承基类方式关键字前面添加一个virtual关键字,表示这个基类是虚基类)。保证最远派生类只保留唯一的基类成员,而不重复保留多份同一基类成员。
2.//test.h=============================================
//类的定义===========================================
#ifndef TEST_H
   #define TEST_H
#include<iostream>
using namespace std;
//========================A======================//
class A{
public:
 int a;
// double d;
 A(){a=100;}
};
//=========================A1==================//
class A1:virtual public A{
public:
 int a1;
};
//=======================A2================//
class A2:virtual public A{
public:
 int a2;
};
//========================B===================//
class B :public A1,public A2{
public:
  int b;
};
#endif
//test.cpp=====================================
//类的实现======================================
#include"test.h"

//main.cpp====================================
//测试虚基类的使用=============================
#include"test.h"
int main(){
    A a0;
 cout<<"sizeof(a0)="<<sizeof(a0)<<endl;
 A1 a1;
 cout<<"sizeof(a1)="<<sizeof(a1)<<endl;
 A2 a2;
 cout<<"sizeof(a2)="<<sizeof(a2)<<endl;
 B b1;
 cout<<"sizeof(b1)="<<sizeof(b1)<<endl;
    cout<<b1.a<<endl;
 return 0;
}
//运行结果
sizeof(a0)=4
sizeof(a1)=12
sizeof(a2)=12
sizeof(b1)=24
100
3.虚基类的成员由最远派生类的构造函数通过调用虚基类的构造函数进行初始化。建立对象时所指定的类为最远派生类。在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出虚基类的构造函数的调用 。如果没有给出,则表示调用该虚基类的缺省构造函数。在建立对象时,只有最远派生类的构造函数调用虚基类的构造函数,该派生类的其他基类对虚基类的构造函数的调用被忽略。
五、抽象类
1.定义:包含纯虚函数的类。其不能用来定义对象。
2.作用:定义一个统一的接口,更好的实现多态。编译器要求在派生类中对纯虚函数必须予以重载以实现多态性,即必须实现它。
3.#include<iostream>
using namespace std;
//==============A类=================// 
class A{
public:
 A(){}
 virtual ~A(){}
 void f1(){
  cout<<"A::f1()"<<endl;
 }
 virtual void f2(){
   cout<<"A::f2()"<<endl;
 }
 virtual void f3()=0;
};

//==============子类B=================//  
class B:public A{
public:
 B(){}
 virtual ~B(){}
 void f1(){
 cout<<"B::f1()"<<endl;
 }
 virtual void f2(){
   cout<<"B::f2()"<<endl;
 }
 virtual void f3(){
   cout<<"B::f3()"<<endl;
 }
};

//==========主函数=====================// 
int main(){
 A *a=new B();
   //A a1;错误,不能实例化抽象类的对象
 a->f1();
 a->f2();
 a->f3();
 delete a;
 return 0;
}
//输出结果
A::f1()
B::f2()
B::f3()
六、基类与派生类对象之间赋值兼容原则
基类对象与派生类对象之间赋值兼容原则:一个公有派生类的对象在使用上可以被当作基类的对象,反之则禁止。也就是说:
(1)可以将派生类的对象赋值给基类对象,反之不对;结果:只是将从基类继承过来的成员赋值,基类对象只能访问派生类中从基类继承的公有成员,不能访问派生类中增加的公有成员。
(2)派生类的对象可以初始化基类的引用;结果:基类对象只能引用派生类从基类继承的成员。
(3)指向基类的指针也可以指向派生类(即可以将一个派生类的对象赋值给基类的指针)。结果:基类的指针只能引用从基类继承来的成员。
//验证将一个派生类的对象赋值给基类的指针
#include<iostream>
using namespace std;
class A0{
public:
void display(){
cout<<"A0::display()"<<endl;
}
};
//========================
class A1:public A0{
public:
void display(){
cout<<"A1::display()"<<endl;
}
};
//=======================
class B0:public A1{
public:
void display(){
cout<<"B0::display()"<<endl;
}
};
//=====================
void fun(A0 *p){
p->display();
}
//=======================
int main(){
A0  a0,*p;
A1  a1;
B0  b0;

p=&a0;
fun(p);

p=&a1;
fun(p);

p=&b0;
fun(p);
return 0;
}
//输出结果:
//A0::display()
//A0::display()
//A0::display()
//================================================
//验证派生类的对象赋值给基类对象
#include<iostream>
using namespace std;
class A{
public:
 int x;
 A(int a=0){
  x=a;
 }
};
class B{
public:
 int y;
 B(int a=0){
  y=a;
 }
};
class C:public A,public B {
 int z;
public:
 C(int a,int b,int m):A(a),B(b){
  z=m;
 }

 void show(){
  cout<<"x="<<x<<"/t"<<"y="<<y<<"/t"<<"z="<<z<<endl;
 }

};

int main(){
    A a(100);
 B b(200);
 C c(10,20,50);

 cout<<"a.x="<<a.x<<endl;
 cout<<"b.y="<<b.y<<endl;
 c.show();
 a=c;//派生类的对象赋值给基类对象
 b=c;//派生类的对象赋值给基类对象
 cout<<"a.x="<<a.x<<endl;
 cout<<"b.y="<<b.y<<endl;
 A *p;
 p=&c;

 return 0;
}
//输出结果
a.x=100;
b.y=200
x=10   y=20   z=50  a.x=10
b.y=20

原创粉丝点击