class a
{
public:
virtual void print(){ //example 2
//void print(){ //example 1
cout<<1<<endl;
}
};
class b: public a
{
public:
void print(){
cout<<2<<endl;
}
};void main(int argc, char* argv[]){
a *pa;
/* start 1 分析结果
理论:用基类的指针或者引用指向派生类对象,通过基类的指针或者引用调用虚函数,实际执行的将是派生类对象中定义的虚函数。
实践:
第一个过程验证的是,基类的a中函数print()在添加virtual和取消的不同
修改代码位置
当结果是:1时,这里是将example 2 注释掉
分析:
这是用基类的变量接收子类的变量。因为不是多态,即,无virtual修饰符,从而调用基类(a)函数的结果
当结果是:2时,这里是将example 1 注释掉
分析:
这里是用基类的变量接收子类的变量。因为是多态,即,含virtual修饰符,从而调用子类(b)函数的结果
*/
//start 1
pa= new d;
pa->print();
//end 1
}
重要的几个点:
1.当一个成员函数(包括析构函数在内)声明为虚函数后,其派生类中的同名函数都自动成为虚函数,无论是否加virtual关键字。
2.用基类的指针或者引用指向派生类对象,通过基类的指针或者引用调用虚函数,实际执行的将是派生类对象中定义的虚函数。
静态连接:
用虚函数实现动态连接在编译期间,C++编译器根据程序传递给函数的参数或者函数返回类型来决定程序使用那个函数,然后编译器用正确的的函数替换每次启动。这种基于编译器的替换被称为静态连接,他们在程序运行之前执行。
动态连接:
当程序执行多态性时,替换是在程序执行期进行的,这种运行期间替换被称为动态连接。
class A
{
public:
virtual void f(){
cout<<"A::f"<<endl;
}
};
class B: public A
{
public:
void f(){
cout<<"B::f"<<endl;
}
};
class C: public A
{
public:
void f(){
cout<<"C::f"<<endl;
}
};
void test(A *a){
a->f();
}
void main(int argc, char* argv[]){
B *b = new B;
C *c = new C;
char choice;
do{
cout<<"Type B for class B, C for class C, but other character can be over"<<endl;
cin>>choice;
if(choice == 'b')
test(b);
else if (choice == 'c')
test(c);
else
break;
}while(1);
cout<<endl<<endl;
}
/*
分析:
存在两个测试点,
1.去除所有f()函数前的所有virtual标识
这种情况下,没有多态性的存在,但也存在一个知识点:基类指针变量可以用子类的变量来复制,并不会报错,反之,要小心,是不允许的
2.去除基类(a)的子类中相应virtual函数标识
这种情况下,仍然是成立的,因为当一个成员函数(包括析构函数在内)声明为虚函数后,其派生类中的同名函数都自动成为虚函数,无论是否加virtual关键字。
*/
class A
{
public:
void fun(){
cout<<"A::fun"<<endl;
}
};
class B: public A
{
public:
void fun(){
cout<<"B::fun"<<endl;
}
void fun0(){
cout<<"B::fun0"<<endl;
}
};
void main(int argc, char* argv[]){
A *a = new A;
B *b = new B;
B *pb;
pb = static_cast<B *>(a);//基类指针向继承类指针进行显示转化
pb->fun0();
pb->fun0();
}
class CBase
{
public:
virtual void fun1(){
cout<<1<<endl;
}
void fun2(){
cout<<2<<endl;
}
};
class CDerived: public CBase
{
public:
void fun1(){
cout<<3<<endl;
}
void fun2(){
cout<<4<<endl;
}
};
void main(int argc, char *argv[]){
CBase base;
CDerived derived;
base=derived;
base.fun1(); //1
base.fun2(); //2
cout<<endl;
derived.fun1(); //3
derived.fun2(); //4
cout<<endl;
//用基类指针获取基类变量
CBase *pb = &base; //这个过程没有运用多态
pb->fun1(); //1
pb->fun2(); //2
cout<<endl;
//用基类指针获取子类变量
pb = &derived;
pb->fun1(); //3
pb->fun2(); //2 因为这不是虚拟函数,且用的变量时CBase* 因此用这个类的函数调用
cout<<endl;
CDerived *pd = (CDerived*)&base;
pd->fun1(); //1 这样运用其实是有问题的,因为用子类的指针指向父类的变量,这个一般不允许,需要添加static_cast<要转变得变量类型指针>
pd->fun2(); //4 因为这不是虚拟函数,且用的变量时CDerived* 因此用这个类的函数调用
cout<<endl;
pd = &derived; //这个过程没有运用多态
pd->fun1(); //3
pd->fun2(); //4
cout<<endl;
//下面的变量定义很特别
CBase &b1 = base;
b1.fun1(); //1
b1.fun2(); //2
cout<<endl;
b1 = derived;
b1.fun1(); //1
b1.fun2(); //2
cout<<endl;
CBase &b2 = derived;//这个是多态的过程
b2.fun1(); //3
b2.fun2(); //2
}