在C++里至少含有一个纯虚函数的类为抽象类,在以前的印象里纯虚函数只能声明在基类,不能在基类实现。 先来复习一下纯虚函数长什么样子
virtual void func() =
0;
现在提出两个问题:
如果在抽象基类里声明了一个纯虚函数,并在抽象基类里实现了纯虚方法会怎样?如果子类继承抽象基类,对于纯虚函数,我们是否可以选择不实现该纯虚函数呢?
答案是: 1. 在子类中实现了纯虚函数(实现就是按照原函数的声明,加上函数体,返回类型,参数类型、参数个数等均不能改变), 那么这个子类就不是抽象类,而是一个具体类,可以创建该类的实例对象,子类要实现抽象类的纯虚方法需要先在类定义里声明; 2. 子类继承抽象基类,如果在定义里没有声明基类的纯虚方法,则默认不实现基类的纯虚方法,该子类依旧是抽象类,不能实例化对象。 图中CollegeStudent类继承了Person类,但没有实现Person类的纯虚方法,在实例化时就出现图中所示错误。
综上所述:
纯虚函数在抽象类里是可以有自己的实现,继承抽象类的子类可以实现纯虚方法,也可以不实现。实现了纯虚方法的子类是具体类,可以实例化,没有实现纯虚方法的子类依旧是抽象类,不能实例化。实现抽象类的纯虚方法需要在子类定义中先声明,没有声明默认不实现该纯虚方法,声明该纯虚方法时要与抽象类的纯虚方法一致。
与java对比了一下发现在java里使用abstract声明的抽象类与C++里使用 vittual 声明的纯虚函数的抽象类是有挺大区别的。 在java里抽象类里声明的抽象方法是不允许有实现的,实现一定要在子类里。而在C++里的类似于抽象方法的纯虚函数,抽象类是可以有实现的! 以下是验证代码:
抽象基类的定义(person.h)
#pragma once
#ifndef PERSON_H_
#define PERSON_H_
#include<string>
using namespace std;
class Person
{
public:
Person();
Person(
int Age,
string Sex,
string Name);
~Person();
int getAge();
string getName();
string getSex();
virtual void show() =
0;
void print();
virtual void updateAge()
{
cout <<
"Person类的updateAge方法:" << endl;
cout <<
this->name <<
"的年龄原来为" <<
this->age << endl;
age = age +
1;
cout <<
this->name <<
"的年龄现在为" <<
this->age << endl;
}
private:
string name;
int age;
string sex;
};
#endif
抽象基类里的一些方法实现(person.cpp)
#include "stdafx.h"
#include<iostream>
#include"person.h"
using namespace std;
void Person::show()
{
cout <<
"调用Person类的抽象虚方法show,我的调用证明了完全虚函数是可以有实现并且可以被调用的" << endl;
cout <<
this->name <<
"信息如下:" << endl;
cout <<
"年龄:" <<
this->age <<
" 性别:" <<
this->sex << endl<<endl;
}
void Person::print()
{
cout <<
this->name <<
"信息如下:" << endl;
cout <<
"年龄:" <<
this->age <<
" 性别:" <<
this->sex << endl;
}
Person::Person()
{
this->age =
19;
this->name =
"张三";
this->sex =
"男";
}
Person::Person(
int Age,
string Sex,
string Name)
{
this->age = Age;
this->name = Name;
this->sex = Sex;
}
Person::~Person()
{
}
int Person::getAge()
{
return age;
}
string Person::getSex()
{
return sex;
}
string Person::getName()
{
return name;
}
实现了抽象类的Student类(Student.h)
#pragma once
#ifndef STUDENT_H_
#define STUDENT_H_
#include<iostream>
#include<string>
#include "person.h"
using namespace std;
class Student :
public Person
{
public:
Student();
Student(
int Age,
string Sex,
string Name);
Student(
int Age,
string Sex,
string Name,
int Sno,
string School);
~Student();
int getSno() {
return sno; };
string getSchool() {
return school; };
void show();
void updateAge();
private:
int sno;
string school;
};
void Student::show()
{
cout <<
"Student类的show方法:" << endl;
this->print();
cout <<
"学号:" <<
this->sno <<
" 就读学校:" <<
this->school << endl << endl;
}
Student::Student()
{
this->sno =
100;
this->school =
"BeiJingUniversity";
}
Student::Student(
int Age,
string Sex,
string Name) :Person(Age,Sex,Name)
{
this->sno =
100;
this->school =
"BeiJingUniversity";
}
Student::Student(
int Age,
string Sex,
string Name,
int Sno,
string School):Person(Age, Sex, Name)
{
this->school = School;
this->sno = Sno;
}
Student::~Student()
{
}
void Student::updateAge()
{
cout <<
"我是Student类里重写的虚方法updateAge\n\n";
}
#endif
一个未实现抽象基类的子类(CollegeStudent.h)
#pragma once
#ifndef COLLEGESTUDENT_H_
#define COLLEGESTUDENT_H_
#include<iostream>
#include<string>
#include "person.h"
using namespace std;
class CollegeStudent :
public Person
{
public:
CollegeStudent();
~CollegeStudent();
void introduce()
{
cout <<
"大学生来自**大学" << endl;
}
private:
string major;
};
CollegeStudent::CollegeStudent()
{
}
CollegeStudent::~CollegeStudent()
{
}
#endif // !COLLEGESTUDENT_H_
主函数
#include "stdafx.h"
#include<iostream
>
#include "person.h"
#include "Student.h"
#include "collegeStudent.h"
using namespace std;
int main()
{
Student
*student
= new Student();
student
->show();
student
->updateAge();
cout
<< endl;
Person
*person
= new Student(
45,
"男",
"李白",
102,
"南方科技大学");
person
->Person
::show();
person
->updateAge();
cout
<< endl;
Student
*test
= new Student(
45,
"男",
"曹操",
101,
"基因大学");
test
->Person
::show();
test
->Person
::updateAge();
cout
<< endl;
return 0;
}
运行结果
从运行结果可以发现纯虚函数在抽象类定义里是除了声明之外也是可以实现的, 并且通过子类实例化父类得到的对象可以通过显式地调用抽象基类的纯虚方法,甚至子类对象显式调用抽象基类的纯虚方法都是允许的。
只用virtual关键字声明的方法为虚方法,可以被继承,继承后可以进行重载,也可以不重载。
如果没有重载虚方法,调用时默认调用的是基类的如果重载了虚方法,在调用最近重载的那个虚方法,比如抽象类A里有一个方法f()是虚方法,类B继承了A并重载了f(), 类C继承了B也重载了f(),当new一个C对象调用f()方法时将会调用C的方法。
B *test=new C();
test->f();
上面的情况调用f()实际上调用的是对象C最近重载的f()方法。
转载请注明原文地址: https://ju.6miu.com/read-968957.html