一:父类指针和子类指针
class A
{
public:
void fun()
{
cout << "调用了类A的void fun()函数" << endl;
}
};
class B:public A
{
public:
void fun1()
{
cout << "调用了类B的void fun1()函数" << endl;
}
};
int main()
{
A *p = new B; //父类指针可以new一个子类对象
//但是不可以通过父类指针调用子类的成员函数
p->fun(); //可以
//p->fun1();//不可以
delete p;
}
说明:父类指针可以指向一个子类对象,但是,子类指针不可以指向一个父类对象。
虽然,父类指针指向一个子类对象,但是如果父类和子类如果有相同的同名,同参函数,但是,调用时调用的还是父类里的函数。例如:
class A
{
public:
void fun()
{
cout << "调用了类A的void fun()函数" << endl;
}
};
class B:public A
{
public:
void fun()
{
cout << "调用了类B的void fun()函数" << endl;
}
};
int main()
{
A *p = new B;
p->fun(); //可以,调用的是cout << "调用了类A的void fun()函数" << endl;
delete p;
}
思考?
如果,想通过定义一个指针就可以调用父类或子类的同名函数,有没有办法?
答:有,虚函数的引入正是为了解决这个问题。
二:虚函数
对于上面的问题,有办法。
但是,对于这个指针和函数都有要求。
指针类型必须是父类指针,而函数的声明必须要加virtual,即虚函数。
class A
{
public:
virtual void fun() //类外定义时不加virtual
{
cout << "调用了类A的void fun()函数" << endl;
}
};
class B:public A
{
public:
void fun() //子类的void fun()函数可以不加virtual
{
cout << "调用了类B的void fun()函数" << endl;
}
};
int main()
{
A *p = new B;//函数有了virtual的修饰后,new谁便调用那个函数
p->fun(); //没加virtual之前,调用的函数以指针类型为准
delete p;
p = new A;
p->fun();
delete p;
}
c++11 final override的应用
final:用在虚函数上,且是在父类中使用。
作用:禁止该函数在子类中重写这个函数。
class A
{
public:
virtual void fun() final //类外定义时不加virtual
{
cout << "调用了类A的void fun()函数" << endl;
}
};
class B:public A
{
public:
void fun() //错误
{
cout << "调用了类B的void fun()函数" << endl;
}
};
override:用在虚函数中,且是在子类中使用。含有覆盖的意思,既然是覆盖,那覆盖前就必须要有和即将覆盖时的相同函数。
作用:防止在子类中,写错虚函数形式(函数返回类型,形参个数)
class A
{
public:
virtual void fun() //类外定义时不加virtual
{
cout << "调用了类A的void fun()函数" << endl;
}
};
class B:public A
{
public:
void fun(int a) override//错误,因为父类中没有void fun(int a)函数
{
cout << "调用了类B的void fun()函数" << endl;
}
};
虚函数总结:实行的是动态绑定,即运行时才知道绑到那个函数去,不能只写函数声明,必须写函数定义。
虚函数用于指针才有意义,用于对象时意义不大。
三:多态性
答:多态性主要针对的是虚函数。
四:纯虚函数
定义:在基类中声明的虚函数,但它在基类中没有定义,且在所有的子类中该函数必须重写。
写法:在函数声明后加=0;
说明:一个类中有了纯虚函数后,那么该类就成了抽象类,即该类不能定义对象。
所有的实现方法是通过子类去实现的。
class A
{
public:
virtual void fun() = 0; //纯虚函数
/*{
cout << "调用了类A的void fun()函数" << endl;
}*/
};
class B:public A
{
public:
void fun()
{
cout << "调用了类B的void fun()函数" << endl;
}
};
int main()
{
A p;//错误,A是一个抽象类
}
五:虚析构
基类的析构函数一般写成虚析构函数
class A
{
public:
A()
{
cout << "调用了A()" << endl;
}
~A()
{
cout << "调用了~A()" << endl;
}
};
class B:public A
{
public:
B()
{
cout << "调用了B()" << endl;
}
~B()
{
cout << "调用~B()"<<endl;
}
};
int main()
{
A *p = new B;
delete p;//没有调用B的析构函数
}
结论:父类指针new一个子类对象,在delete时,不会调用子类的析构函数。