C++ 无法在C+;中调用派生类函数+;
我肯定我漏掉了部分密码 我有以下代码:C++ 无法在C+;中调用派生类函数+;,c++,C++,我肯定我漏掉了部分密码 我有以下代码: #include <iostream> using namespace std; class Record { private: int age; string name; public: virtual int getType()=0; }; class Student: public Record { private: int level_; public: Student()
#include <iostream>
using namespace std;
class Record
{
private:
int age;
string name;
public:
virtual int getType()=0;
};
class Student: public Record
{
private:
int level_;
public:
Student()
{
level_=1;
};
~Student() {};
int getType()
{
return 1;
}
int level()
{
return level_;
}
};
int main (int argc, char ** argv)
{
Record *r = new Student();
cout <<"tuype " << r->getType();
cout <<"Class " << r->level();
}
#包括
使用名称空间std;
课堂记录
{
私人:
智力年龄;
字符串名;
公众:
虚拟int getType()=0;
};
班级学生:公开记录
{
私人:
国际水平!;
公众:
学生()
{
级别=1;
};
~Student(){};
int getType()
{
返回1;
}
整数级()
{
返回水平;
}
};
int main(int argc,字符**argv)
{
记录*r=新学生();
cout记录中缺少virtual method level()声明。另外,为了防止资源泄漏,您需要在记录中定义虚拟析构函数
class Record
{
...
public:
virtual ~Record() {}
virtual int level() = 0;
virtual int getType() = 0;
};
更改记录以进行level()
virtual
你写道:
Record *r = new Student();
在这一行之后,编译器将r
视为指向记录
或某个记录
派生类(它是派生类)的指针,但它只知道为记录
指定的接口。没有虚拟
级别()记录
中的
功能,因此您无法通过记录
界面访问学生
的级别功能。只需将此功能添加到记录
,您就可以:
virtual int level() { return 0; } // Student may override implementation
或
另一种选择:检查记录*是否针对学生
我上面说
Record
中没有virtual
level()
函数,因此您无法通过Record
界面访问学生的level函数
…并显示如何添加到记录
界面,但另一种方法是再次访问学生
界面,如中所示:
if (Student* p = dynamic_cast<Student*>(r))
std::cout << "Level " << p->level() << '\n';
这确保在使用基类指针(例如,如果在main()
的底部添加delete r;
)删除派生对象时调用派生类的析构函数实现(编译器仍将确保随后调用基类析构函数)
如果不这样做,这是未定义的行为,并且充其量您会发现在派生类中添加的任何其他数据成员都没有调用它们的数据成员…对于无害的int
,但是对于std::string
,它可能会泄漏内存,甚至会持有锁,导致程序稍后挂起。当然,这不是一个好方法依赖于最佳情况下未定义的行为的想法;-)但我认为了解什么绝对不会发生是有用的,除非您将基本析构函数设置为虚拟的
建议对学生进行一些小的改进
如果您在记录中使级别虚拟,那么为了让学生类的读者更清楚地知道级别()
是从基类实现的虚拟函数,如果您有一个具有适当C++11能力的编译器,您可以使用覆盖关键字:
int level() override
{
return level_;
}
如果在基类中找不到匹配的(non-const
)virtual int level()
,这将导致编译器错误,因此它可以避免一些偶然的故障排除。如果您觉得virtual
关键字有文档价值,也可以重复该关键字(对于C++03特别好,其中覆盖
不是一个选项),但它不会造成任何功能上的差异-函数保持虚拟
,只要它是(隐式或显式的)从基类重写虚函数。因为记录
类对名为level()的函数一无所知。
您需要在基类中创建一个虚拟的level()
函数。在基类中创建虚拟函数,如
virtual int level() = 0;
一旦您在基类记录中创建了虚拟函数level()
,学生就必须在学生类中拥有它的函数level()
。目前您在类记录中没有虚拟level()
函数,因此您无法访问学生类的level()
函数当前正在使用基类记录。编译时,应收到类似以下内容的错误消息:
error C2039: 'level' : is not a member of 'Record'
您需要在Record类中添加以下内容:
virtual int level()=0;
您无法调用r->level()
,因为您试图调用一个类记录中不存在的函数。在您的特定情况下,r
指向的数据不仅是Record
,同时也是学生,因此您可以选择:
Student *r = new Student();
cout <<"tuype " << r->getType();
cout <<"Class " << r->level()
另一个问题:您应该将Record
类中的析构函数标记为virtual,因为当您删除r
时,学生的构造函数将不会被调用学生实例通过以下方式被升级为Record:
Record *r = new Student();
在保存一个学生实例时,r代表记录。r->getType()函数调用使用C++的多态机制绑定到Student::getType。
要调用level()函数,可以:
1. Add a virtual function level() to Record class.
2. downcasting r to Student class, as follows:
1.向Record类添加虚拟函数级别()。
2.将r向下播送至学生班级,如下所示:
Student*r\u new=dynamic\u cast(r);
r_new->level();
你的Record
类应该有一个虚拟析构函数。你的Student
类应该有一个隐式定义的析构函数。并且你的函数都不需要在主体后加分号。我认为通常使用方法getType()不是一个好主意
。这并不总是一件坏事,但如果可能的话,请尽量避免。不要忘记为继承设计的类中的虚拟析构函数,它非常有用important@chris:+1,用于虚拟析构函数建议,但无论Student
是否有隐式定义的析构函数,分号,shiver;-).@TonyD,不在这里,但是当你进入有影响的领域时,把一个放在自己身上只会给你带来劣势。@chris:cou
Record *r = new Student();
cout <<"tuype " << r->getType();
cout <<"Class " << dynamic_cast<Student*>(r)->level()
class Record { ...
virtual int level() = 0;
}
Record *r = new Student();
1. Add a virtual function level() to Record class.
2. downcasting r to Student class, as follows:
Student *r_new = dynamic_cast<Student>(r);
r_new->level();