C++基础之关键字——virtual详解
virtual
C++中的virtual关键字主要有这样⼏种使⽤场景:第⼀,修饰⽗类中的函数 ;第⼆,修饰继承性。注意:友元函数、构造函数、static静态函数不能⽤virtual关键字修饰。普通成员函数和析构函数可以⽤virtual关键字修饰。
virtual具有继承性:⽗类中定义为virtual的函数在⼦类中重写的函数也⾃动成为虚函数。
⼀定要注意: 只有⼦类的虚函数和⽗类的虚函数定义完全⼀样才被认为是虚函数,⽐如⽗类后⾯加了const,如果⼦类不加的话就是隐藏了,不是覆盖.
山东省经济管理干部学院修饰⽗类中的函数金貂取酒
修饰⽗类中的函数主要分为三种:普通函数、析构函数和纯虚函数。
修饰⽗类中的普通函数
被修饰的函数称为虚函数, 是C++中多态的⼀种实现(多说⼀句,多态分编译时多态-通过重载实现和运tagged
⾏时多态-通过虚函数实现)。 也就是说⽤⽗类的指针或者引⽤指向其派⽣类的对象,当使⽤指针或引⽤调⽤函数的时候会根据具体的对象类型调⽤对应对象的函数(需要两个条件:⽗类的函数⽤virtual修饰和⼦类要重写⽗类的函数)。下⾯⽤⼀个例⼦来说明:
#include<iostream>
class father {
public:
void func1(){std::cout <<"this is father func1"<< std::endl;}
virtual void func2(){std::cout <<"this is father func2"<< std::endl;
}
class son:public father {
public:
void func1(){std::cout <<"this is son func1"<< std::endl;}
void func2(){std::cout <<"this is son func2"<< std::endl;
}
int main(){
father *f1 =new son();
f1.func1();bard
f1.func2();
return0;
}
output:
this is father func1
this is son func2
通过上⾯的例⼦可以看出,使⽤virtual修饰的函数会根据实际对象的类型来调⽤,没有使⽤virtual修饰的根据指针的类型来调⽤。虚函数最关键的特点是“动态联编”,它可以在运⾏时判断指针指向的对象,并⾃动调⽤相应的函数。
修饰析构函数
修饰析构函数与上⾯讲到的使⽤⽅法和原理相同,虚析构函数在销毁时会调⽤对象的析构函数,这样就不会出现像有的数据成员没有销毁导致内存泄露的问题或者程序直接崩溃。下⾯也⽤⼀个例⼦说明:
};
class Father:public GrandFather{
public:
Father(){std::cout <<"construct father"<< std::endl;}
~Father(){std::cout <<"destruct father"<< std::endl;}
};
class Son:public Father{
zc
public:
Son(){std::cout <<"construct son"<< std::endl;}
~Son(){std::cout <<"destruct son"<< std::endl;}
};
int main(){
Father *f =new Son();
delete f;
return0;
}
output:
construct grandfather
construct father
construct son
destruct fatherdrenched什么意思
destruct grandfather
我们发现没有调⽤son的析构函数,当将Father或者GrandFather其中⼀个的析构函数修改为virtual后输出就变为了
construct grandfather
construct father
construct son
destruct son
destruct father
destruct grandfather
纯虚函数
纯虚函数的定义是在虚函数的后⾯加⼀个=0。定义了纯虚函数的类是⼀个抽象类。
virtual void func()=0;
纯虚函数需要注意这⼏点:
1.定义了纯虚函数的类不能够实例化,也就是不能够创建对象
2.继承了含有纯虚函数的⽗类的⼦类如果没有实现纯虚函数也不能够实例化
修饰继承性
假如有这种场景,⼀个类继承两个或者更多的⽗类,但是这些⽗类⾥⼜有⼀些有共同的⽗类,会出现什么情况呢?
};
class Father1:public GrandFather{
public:
Father1(){std::cout <<"construct father1"<< std::endl;}
~Father1(){std::cout <<"destruct father1"<< std::endl;}
};
class Father2:public GrandFather{
public:
Father2(){std::cout <<"construct father2"<< std::endl;}
牛奶歌下载~Father2(){std::cout <<"destruct father2"<< std::endl;}
};
class Son:public Father1, Father2{
public:
Son(){std::cout <<"construct son"<< std::endl;}
~Son(){std::cout <<"destruct son"<< std::endl;}
depan};
int main(){
Father *f =new Son();
delete f;
return0;
}
output:
construct grandfather
construct father1
georgeconstruct grandfather
construct father2
construct son
destruct son
destruct father2
destruct grandfather
英语谚语destruct father1
destruct grandfather
通过这个例⼦我们看到创建⼀个son会创建两个grandfather,不符合我们的预期啊,⽽且还可能会导致程序挂掉。这⾥就请virtual出场了,当把father1和father2继承grandfather修改为virtual继承(也就是在public前⾯加⼀个virtual)的时候输出会变成这样:
output:
construct grandfather
construct father1
construct father2
construct son
destruct son
destruct father2
destruct father1
destruct grandfather
这⽐较符合我们的预期。