联编和虚函数
时间:2010-11-19 来源:osullishuai80
一、联编
(1)联编是指一个计算机程序自身彼此关联的过程,可分为静态联编和动态联编.
(2)静态联编
联编工作出现在编译连接阶段,这种联编又称作早期联编,因为联编过程是在程序开始之前完成的.
(3)动态联编
编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序运行时才能确定将要调用的函数,这要求联编工作要在程序运行时进行,这种在程序运行时进行联编工作称作动态联编
例程:
#include <iostream.h>
class Base
{
public:
void fun()
{
cout<<"In Base class!"<<endl;
}
};
class SubClass:public Base
{
public:
void fun()
{
cout<<"In SubClass!"<<endl;
}
};
class SubClass2:public Base
{
public:
void fun()
{
cout<<"In SubClass2!"<<endl;
}
};
void test(Base &b)
{
b.fun();
} int main()
{
Base bc;
SubClass sc;
cout<<"Call test(bc)"<<endl;
test(bc);
cout<<"Call test(sc)"<<endl;
test(sc);
}
执行结果:
Call test(bc)
In Base class!
Call test(sc)
In Base class!
Attention!!!
函数test()的形参是类Base的别名,因此无论传递什么类型的参数,都会执行类Base的成员函数fun(),而不会执行派生类的成员函数fun().但程序员的意思是要执行派生类的成员函数fun(),执行结果明显偏离了程序员的意思.在C++中有没有什么机制可以阻止这种情况的发生呢?这就是虚函数. 二、虚函数
(1)虚函数的定义
虚函数是非static型的成员函数.在C++中它的定义格式是:
virtual <类型说明符><函数名>(<参数表>)
(2)虚函数的应用场合
当基类的引用(或指针)指向某个派生类对象时,若不使用虚函数,则调用时都会调用基类中定义的函数,如上例中程序会调用基类中的函数fun(),而不会调用派生类的成员函数fun().为此,需要明确三个前提,只有这三个前提满足时才会使用虚函数.
<1>在基类中派生出派生类
<2>基类的引用(或指针)指向派生类的某个对象
<3>在派生类中存在和基类中相同的函数
1.派生类中与基类虚函数有相同的参数个数
2.派生类中该函数的参数类型与基类的虚函数的对应参数类型相同
3.派生类中该还念书的返回值与基类函数相同
此时,可以将基类中的该函数定义为虚函数,当基类的引用(或指针)指向不同的派生类对象时,则会调用其真正指向对象的成员函数而不是基类中定义的成员函数.
Attention!!!
1.满足上述条件的派生类成员函数自然是虚函数,因此可以不必加virtual说明.
2.为什么满足了上述三个条件时必须使用虚函数?这是因为在基类和派生类中具有相同的函数(返回值类型、参数个数、参数类型),而派生类空间是对基类空间的继承,此时在派生类空间内有两个完全相同的函数.在派生类中的内存中如何分辨呢,通常有两种方法.一种是使用作用域运算符("::")唯一标识并分别访问.二是将从基类中继承的成员对象设置为虚函数.在下例中,派生类空间内既有基类的成员函数fun(),也有派生类自己的成员函数fun(),程序员可通过上述两种方法来区分这两个函数.
例程:
#include <iostream.h>
class Base
{
public:
virtual void fun() //定义与派生类函数fun()相同的基类中函数fun()为虚函数
{
cout<<"In Base class!"<<endl;
}
};
class SubClass:public Base
{
public:
void fun() //与基类中的虚函数完全相同(返回值类型、参数个数、参数类型)
{
cout<<"In SubClass!"<<endl;
}
};
void test(Base &b) //函数参数为基类的引用
{
b.fun();
} int main()
{
Base bc;
SubClass sc;
cout<<"Call test(bc)"<<endl;
test(bc);
cout<<"Call test(sc)"<<endl;
test(sc); //基类Base引用(或指针)指向派生类SubClass的对象sc
}
执行结果:
Call test(bc)
In Base class!
Call test(sc)
In SubClass!
三、抽象类和纯虚函数
(1)纯虚函数是一种特殊的虚函数,它的一般格式如下:
class <类名>
{
virtual <类型><函数名>(<参数表>)=0;
}
(2)抽象类:带有纯虚函数的类称作抽象类.
1.抽象类不能创建对象.
2.抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出.若派生类中没有重定义纯虚函数,则该派生类仍为抽象类.
例程:
#include <iostream.h>
class Vehicle
{
protected:
float speed;
int total;
public:
Vehicle(float speed,int total)
{
Vehicle::speed = speed;
Vehicle::total = total;
}
virtual void ShowMember()=0; //定义纯虚函数
};
class Car:public Vehicle
{
protected:
int aird;
public:
Car(int aird,float speed,int total):Vehicle(speed,total)
{
Car::aird = aird;
}
virtual void ShowMember()//=0;//派生类成员函数重载
{
cout<<speed<<"|"<<total<<"|"<<aird<<endl;
}
};
int main()
{
//Vehicle a(100,4); //错误,抽象类不能创建对象
Car b(250,150,4);
b.ShowMember();
return 0;
}
Attention!!!
1.抽象类不能创建某个具体的对象.
2.若在派生类中写成"virtual void ShowMember()=0",则该派生类仍为抽象类,同样也不能创建某个具体的对象. 四、虚析构函数
(1)在析构函数前面加上关键字virtual进行说明,称该析构函数为虚析构函数.
(2)构造函数不能是虚函数.
(3)若一个基类的析构函数被说明为虚析构函数,则它的派生类中的析构函数也是虚函数.
(4)说明虚析构函数目的在于使用delete运算符删除一个对象时,能保证析构函数被正确的执行.因为设置虚析构函数后,可以采用动态联编的方式选择析构函数.
例程:
#include <iostream.h>
#include <stdlib.h>
class ClxBase
{
public:
ClxBase() //基类构造函数
{
cout<<"construct Base class!"<<endl;
};
virtual ~ClxBase() {cout<<"in destructor of class ClxBase"<<endl;}; //虚析构函数
virtual void DoSomething(){cout<<"Do something in class ClxBase!"<<endl;};//虚函数
//void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
};
class ClxDerived : public ClxBase
{
public:
ClxDerived()//派生类构造函数
{
cout<<"construct Sub class!"<<endl;
};
~ClxDerived() {cout<<"Output from the destructor of class ClxDerived!"<<endl;};//虚析构函数 void DoSomething()//与基类的虚函数相同(返回值类型、参数个数、参数类型)
{
cout << "Do something in class ClxDerived!" << endl;
};
}; void main()
{
ClxBase *pTest = new ClxDerived; //创建一指向派生类的基类指针
pTest->DoSomething(); //执行派生类的相应的函数
delete pTest; //删除派生类的对象
}
执行结果:
construct Base class!
construct Sub class!
Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
in destructor of class ClxBase
Attention!!!
(1)第一条语句:
创建一指向派生类的基类指针,此时符合需要创建虚函数的三个条件,即:
1.由基类派生出派生类
2.基类的指针指向派生类的某个对象
3.在派生类中存在和基类中相同的函数void DoSomething(),即返回值类型、参数个数、参数类型均相同.
(2)第二条语句:
通过基类的指针来调用派生类的函数void DoSomething(),由于符合创建虚函数的三个条件,因此必须将基类中的函数void DoSomething()定义为虚函数,这样通过该指针才能正确的调用派生类的函数void DoSomething(),否则仍调用的是基类的函数void DoSomething().因此,若执行基类中被屏蔽的语句,则输出结果为:
construct Base class!
construct Sub class!
Do something in class ClxBase!
Output from the destructor of class ClxDerived!
in destructor of class ClxBase
(3)第三条语句:
该语句删除了指向
(1)联编是指一个计算机程序自身彼此关联的过程,可分为静态联编和动态联编.
(2)静态联编
联编工作出现在编译连接阶段,这种联编又称作早期联编,因为联编过程是在程序开始之前完成的.
(3)动态联编
编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序运行时才能确定将要调用的函数,这要求联编工作要在程序运行时进行,这种在程序运行时进行联编工作称作动态联编
例程:
#include <iostream.h>
class Base
{
public:
void fun()
{
cout<<"In Base class!"<<endl;
}
};
class SubClass:public Base
{
public:
void fun()
{
cout<<"In SubClass!"<<endl;
}
};
class SubClass2:public Base
{
public:
void fun()
{
cout<<"In SubClass2!"<<endl;
}
};
void test(Base &b)
{
b.fun();
} int main()
{
Base bc;
SubClass sc;
cout<<"Call test(bc)"<<endl;
test(bc);
cout<<"Call test(sc)"<<endl;
test(sc);
}
执行结果:
Call test(bc)
In Base class!
Call test(sc)
In Base class!
Attention!!!
函数test()的形参是类Base的别名,因此无论传递什么类型的参数,都会执行类Base的成员函数fun(),而不会执行派生类的成员函数fun().但程序员的意思是要执行派生类的成员函数fun(),执行结果明显偏离了程序员的意思.在C++中有没有什么机制可以阻止这种情况的发生呢?这就是虚函数. 二、虚函数
(1)虚函数的定义
虚函数是非static型的成员函数.在C++中它的定义格式是:
virtual <类型说明符><函数名>(<参数表>)
(2)虚函数的应用场合
当基类的引用(或指针)指向某个派生类对象时,若不使用虚函数,则调用时都会调用基类中定义的函数,如上例中程序会调用基类中的函数fun(),而不会调用派生类的成员函数fun().为此,需要明确三个前提,只有这三个前提满足时才会使用虚函数.
<1>在基类中派生出派生类
<2>基类的引用(或指针)指向派生类的某个对象
<3>在派生类中存在和基类中相同的函数
1.派生类中与基类虚函数有相同的参数个数
2.派生类中该函数的参数类型与基类的虚函数的对应参数类型相同
3.派生类中该还念书的返回值与基类函数相同
此时,可以将基类中的该函数定义为虚函数,当基类的引用(或指针)指向不同的派生类对象时,则会调用其真正指向对象的成员函数而不是基类中定义的成员函数.
Attention!!!
1.满足上述条件的派生类成员函数自然是虚函数,因此可以不必加virtual说明.
2.为什么满足了上述三个条件时必须使用虚函数?这是因为在基类和派生类中具有相同的函数(返回值类型、参数个数、参数类型),而派生类空间是对基类空间的继承,此时在派生类空间内有两个完全相同的函数.在派生类中的内存中如何分辨呢,通常有两种方法.一种是使用作用域运算符("::")唯一标识并分别访问.二是将从基类中继承的成员对象设置为虚函数.在下例中,派生类空间内既有基类的成员函数fun(),也有派生类自己的成员函数fun(),程序员可通过上述两种方法来区分这两个函数.
例程:
#include <iostream.h>
class Base
{
public:
virtual void fun() //定义与派生类函数fun()相同的基类中函数fun()为虚函数
{
cout<<"In Base class!"<<endl;
}
};
class SubClass:public Base
{
public:
void fun() //与基类中的虚函数完全相同(返回值类型、参数个数、参数类型)
{
cout<<"In SubClass!"<<endl;
}
};
void test(Base &b) //函数参数为基类的引用
{
b.fun();
} int main()
{
Base bc;
SubClass sc;
cout<<"Call test(bc)"<<endl;
test(bc);
cout<<"Call test(sc)"<<endl;
test(sc); //基类Base引用(或指针)指向派生类SubClass的对象sc
}
执行结果:
Call test(bc)
In Base class!
Call test(sc)
In SubClass!
三、抽象类和纯虚函数
(1)纯虚函数是一种特殊的虚函数,它的一般格式如下:
class <类名>
{
virtual <类型><函数名>(<参数表>)=0;
}
(2)抽象类:带有纯虚函数的类称作抽象类.
1.抽象类不能创建对象.
2.抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出.若派生类中没有重定义纯虚函数,则该派生类仍为抽象类.
例程:
#include <iostream.h>
class Vehicle
{
protected:
float speed;
int total;
public:
Vehicle(float speed,int total)
{
Vehicle::speed = speed;
Vehicle::total = total;
}
virtual void ShowMember()=0; //定义纯虚函数
};
class Car:public Vehicle
{
protected:
int aird;
public:
Car(int aird,float speed,int total):Vehicle(speed,total)
{
Car::aird = aird;
}
virtual void ShowMember()//=0;//派生类成员函数重载
{
cout<<speed<<"|"<<total<<"|"<<aird<<endl;
}
};
int main()
{
//Vehicle a(100,4); //错误,抽象类不能创建对象
Car b(250,150,4);
b.ShowMember();
return 0;
}
Attention!!!
1.抽象类不能创建某个具体的对象.
2.若在派生类中写成"virtual void ShowMember()=0",则该派生类仍为抽象类,同样也不能创建某个具体的对象. 四、虚析构函数
(1)在析构函数前面加上关键字virtual进行说明,称该析构函数为虚析构函数.
(2)构造函数不能是虚函数.
(3)若一个基类的析构函数被说明为虚析构函数,则它的派生类中的析构函数也是虚函数.
(4)说明虚析构函数目的在于使用delete运算符删除一个对象时,能保证析构函数被正确的执行.因为设置虚析构函数后,可以采用动态联编的方式选择析构函数.
例程:
#include <iostream.h>
#include <stdlib.h>
class ClxBase
{
public:
ClxBase() //基类构造函数
{
cout<<"construct Base class!"<<endl;
};
virtual ~ClxBase() {cout<<"in destructor of class ClxBase"<<endl;}; //虚析构函数
virtual void DoSomething(){cout<<"Do something in class ClxBase!"<<endl;};//虚函数
//void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
};
class ClxDerived : public ClxBase
{
public:
ClxDerived()//派生类构造函数
{
cout<<"construct Sub class!"<<endl;
};
~ClxDerived() {cout<<"Output from the destructor of class ClxDerived!"<<endl;};//虚析构函数 void DoSomething()//与基类的虚函数相同(返回值类型、参数个数、参数类型)
{
cout << "Do something in class ClxDerived!" << endl;
};
}; void main()
{
ClxBase *pTest = new ClxDerived; //创建一指向派生类的基类指针
pTest->DoSomething(); //执行派生类的相应的函数
delete pTest; //删除派生类的对象
}
执行结果:
construct Base class!
construct Sub class!
Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
in destructor of class ClxBase
Attention!!!
(1)第一条语句:
创建一指向派生类的基类指针,此时符合需要创建虚函数的三个条件,即:
1.由基类派生出派生类
2.基类的指针指向派生类的某个对象
3.在派生类中存在和基类中相同的函数void DoSomething(),即返回值类型、参数个数、参数类型均相同.
(2)第二条语句:
通过基类的指针来调用派生类的函数void DoSomething(),由于符合创建虚函数的三个条件,因此必须将基类中的函数void DoSomething()定义为虚函数,这样通过该指针才能正确的调用派生类的函数void DoSomething(),否则仍调用的是基类的函数void DoSomething().因此,若执行基类中被屏蔽的语句,则输出结果为:
construct Base class!
construct Sub class!
Do something in class ClxBase!
Output from the destructor of class ClxDerived!
in destructor of class ClxBase
(3)第三条语句:
该语句删除了指向
相关阅读 更多 +