目录
以下代码在wn10 cygwin gcc 11.4中调试通过?
class base{
public:
virtual void abc(){
cout<<"base.abc"<<endl;
}
};
class myclass:public base{
public:
void abc() override{
cout<<"myclass.abc"<<endl;
}
};
int main()
{
(new myclass)->abc();
return 0;
}
运行结果:
myclass.abc
从代码上来看,定义虚函数的方式是对的,在子类中用同名函数重写了子类的函数
这并非虚函数使用的真实意图
因为上面的代码即使不用virtual,或者override定义虚函数,照样可以完成相同效果,举例
class base{
public:
void abc(){
cout<<"base.abc"<<endl;
}
};
class myclass:public base{
public:
void abc() {
cout<<"myclass.abc"<<endl;
}
};
再运行,结果也是一样的
myclass.abc
那么虚函数正确的使用应该什么样子?举例代码如下
class base{
public:
void abc(){
cout<<"base.abc"<<endl;
}
void ccc(){
this->abc();
}
};
class myclass:public base{
public:
void abc(){
cout<<"myclass.abc"<<endl;
}
};
int main(){
(new myclass)->ccc();
return 0;
}
以上代码输出
base.abc
从代码上看,这个结果是正确的,调用逻辑也对。把上面的代码改一改
class base{
public:
virtual void abc(){
cout<<"base.abc"<<endl;
}
void ccc(){
this->abc();
}
};
class myclass:public base{
public:
void abc() override{
cout<<"myclass.abc"<<endl;
}
};
然后在运行,这次输出如下
myclass.abc
class base{
public:
virtual void abc(){
cout<<"base.abc"<<endl;
}
/*其他代码*/
};
class myclass:public base{
public:
void abc() override{
cout<<"myclass.abc"<<endl;
}
};
class yourclass:public base{
public:
void abc() override{
cout<<"yourclass.abc"<<endl;
}
};
int main(){
base *b1 = nullptr;
if(/**/){
b1 = new myclass();
}else{
b1 = new yourclass();
}
b1->abc();
return 0;
}
以上代码如果调用了if内,则使用了myclass 的abc,否则就使用了yourclass的abc
这样,通过业务需求来调用不同的abc,就实现了不同逻辑的调用
从以上介绍可以了解到,定义虚函数使用的方法,使用两个关键字,如下:
virtual:关键字声明一个虚拟函数或一个虚拟基类
override:说明一个函数是重写函数,实际上它并非关键字,仅是一个说明符,如下代码
int override = 1;
运行会发现,这句话并不报错,说明override并不是关键字
同时,在重写virtual定义的虚函数时,override可有可无,只要定义方式对,就可以
但是如果定义方式有差别,使用override 可以检测定义是否正确,举例如下
class base{
public:
virtual void abc() const{
cout<<"base"<<endl;
};
};
class myclass:public base{
public:
void abc(){
cout<<"myclass"<<endl;
}
};
基类中的abc定义了const,myclass中的abc没有写const,也就是没有完整定义,这样,是无法覆盖的基类的
如果这个时候myclsss中的abc加上了override,则会提示错误
error: 'void myclass::abc()' marked 'override', but does not override
如果没有override,但在子类中完整定义后也没有问题了,如下写法
class myclass:public base{
public:
void abc() const{
cout<<"myclass"<<endl;
}
};
定义一个抽象类,并不使用任何关键字,它只是个概念,只要是类中有一个格式如下的函数定义,它就是抽象类
virtual void abc() = 0;
这样的函数,被成为纯虚函数,它是一个没有函数内容的函数,仅用来被重写
抽象类不能被实例化,举例如下
class base{
public:
virtual void abc() = 0;
};
int main(){
base b;
return 0;
}
Variable type 'base' is an abstract class
抽象类只能用于被继承,且虚函数必须被子类重写,举例如下
class base{
public:
virtual void abc() = 0;
};
class myclass:public base{
public:
void abc(){
cout<<"myclass"<<endl;
}
};
在C++是允许多继承的,但是多继承的会出现一个问题,就是构造函数调用的问题,举例如下
class base{
public:
base(){
cout<<"base"<<endl;
};
};
class class_1:public base{
public:
class_1(){
cout<<"class_1"<<endl;
}
};
class class_2:public base{
public:
class_2(){
cout<<"class_2"<<endl;
}
};
class myclass:public class_2,public class_1{};
int main(){
myclass m;
return 0;
}
以上代码,class_1,class_2继承了base,myclass又同时继承了class_1,class_2
运行后,输出如下
base
class_2
base
class_1
可以看到base的构造函数被调用了两次,这个结果,可能是需要的,但大多数情况下可能你不需要,如果不需要,这个时候,就需要用虚基类来解决这个问题
修改以上代码,给class_1,class_2继承base时加上virtual关键字,如下,其他代码不变
class class_1:virtual public base{
public:
class_1(){
cout<<"class_1"<<endl;
}
};
class class_2:virtual public base{
public:
class_2(){
cout<<"class_2"<<endl;
}
};
然后运行
base
class_2
class_1
可以看到,base构造函数就调用了一次。这就是虚基类的作用。原本在没有虚基类的情况下,base会依据被继承的情况,出现多个,但使用了虚基类后,基类就只会保留一个副本