指出以下代码中的错误和缺陷

mltong 2011-07-13 10:56:39
以下是一个关于学生对象的接口和实现类的设计实现以及测试代码,请指出其中的错误和缺陷(从语法到编译执行的整个过程),并简要说明原因。


#include <iostream>
using namespace std;

class IStudent
{
public:
virtual ~IStudent() = 0;
virtual const char* GetName() = 0;
virtual int GetAge() = 0;
};

class CStudent : public IStudent
{
public:
CStudent(char *strName, int nAge)
: m_strName(strName)
, m_nAge(nAge)
{
}

virtual ~CStudent()
{
}

virtual const char* GetName() const
{
return m_strName.c_str();
}

virtual int GetAge() const
{
return m_nAge;
}

private:
string m_strName;
int m_nAge;
};

int main()
{
const char *strName = "LiLei";
IStudent *pStudent = new CStudent(strName, 24);
cout << "Name: " << pStudent->GetName() << ", Age: " << pStudent->GetAge() << endl;

return 0;
}

...全文
521 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
至善者善之敌 2011-07-13
  • 打赏
  • 举报
回复
玄机逸士 有点老师的味道
pathuang68 2011-07-13
  • 打赏
  • 举报
回复
12楼中的第1、5和6三点估计是老师最想考大家的地方。
pathuang68 2011-07-13
  • 打赏
  • 举报
回复
我来说几点:
1. 析构函数绝大部分情况下,不能设为纯虚函数
2. 基类的析构函数,通常情况下都要设为虚函数
3. 既然用了string,为啥又要用char*?在这里根本不需要用char*,编程风格混乱,容易造成错误和部必要的麻烦。
4. 下面这样的写法应该是错误的

CStudent(char *strName, int nAge)
: m_strName(strName)
, m_nAge(nAge)

因为,在初始化列表中m_strName(strName)这样的写法,类似于m_strName = strName; 而m_strName的类型是string, strName又是char*,类型根本不匹配,必然会报错。进一步,即便m_strName的类型也是char*,这样写也将是错误的,因为char*不能这样初始化或者赋值的。
5. 基类中的GetName和GetAge,并没有重写基类中的两个纯虚函数,而是积累中GetName和GetAge的重载。尽管其它都一样,但派生类中的GetName和GetAge函数最后都多了个const,这就构成了重载(overload)而非重写(override或overwrite)
6. 基于5的分析,基类中的两个纯虚函数并没有在派生类中重写,因此在派生类中也就存在这两个纯虚函数,因此派生类也是抽象类,而抽象类是不能实例化的,因此在main函数中

IStudent *pStudent = new CStudent(strName, 24);

这样的写法就会报错。

俺木有编译你的程序,稍微看了一下楼主的程序,所以只能给出上面的一些看法(有经验的C++程序员不用编译,都能发现这些问题)。仅供参考。
至善者善之敌 2011-07-13
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 pfdai_hnu 的回复:]
C/C++ code

const char *strName = "LiLei";//函数参数类型不匹配
char *strName = "LiLei";
IStudent *pStudent = new CStudent(strName, 24);//IStudent含有纯虚函数则不能定义相应对象
CStudent *pStudent = new CStudent(strName, ……
[/Quote]

抽象类是可以定义对象指针的,看我改的吧


class IStudent
{
public:
virtual ~IStudent(){};
virtual const char* GetName() = 0;
virtual int GetAge() = 0;
};

class CStudent : public IStudent
{
public:
CStudent(const char *strName, int nAge)
: m_strName(strName)
, m_nAge(nAge)
{
}

virtual ~CStudent()
{
}

virtual const char* GetName()
{
return m_strName.c_str();
}

virtual int GetAge()
{
return m_nAge;
}

private:
string m_strName;
int m_nAge;
};

int main()
{
const char *strName = "LiLei";
IStudent *pStudent = new CStudent(strName, 24);
cout << "Name: " << pStudent->GetName() << ", Age: " << pStudent->GetAge() << endl;

return 0;
}


pfdai_hnu 2011-07-13
  • 打赏
  • 举报
回复

virtual ~IStudent() = 0;//不能声明为纯虚。因为派生类的析构函数会自动调用基类的析构函数,那样连接器会找不到基类的析构函数。
virtual const char* GetName() const//子类和父类函数类型不一致,去掉const
virtual const char* GetName()
地下室小红叔 2011-07-13
  • 打赏
  • 举报
回复
4楼8楼
pfdai_hnu 2011-07-13
  • 打赏
  • 举报
回复

const char *strName = "LiLei";//函数参数类型不匹配
char *strName = "LiLei";
IStudent *pStudent = new CStudent(strName, 24);//IStudent含有纯虚函数则不能定义相应对象
CStudent *pStudent = new CStudent(strName, 24);
mltong 2011-07-13
  • 打赏
  • 举报
回复
去掉了虚析构函数,这个是不妥的吧 delete pStudent
[Quote=引用 3 楼 newfarmerchi 的回复:]

C/C++ code

#include <iostream>
#include <string>
using namespace std;

class IStudent
{
public:
//virtual ~IStudent() = 0;
virtual const char* GetName() = 0;
virtual int GetAge() = 0;
}……
[/Quote]
mltong 2011-07-13
  • 打赏
  • 举报
回复
忘了给大家说了,不要自己编译,就当是一个卷子……
xiaojunjun1202 2011-07-13
  • 打赏
  • 举报
回复
又是学生题?
至善者善之敌 2011-07-13
  • 打赏
  • 举报
回复

Error 1 error C2259: 'CStudent' : cannot instantiate abstract class c:\documents and settings\administrator\桌面\mfc程序\vs2005\vs2005.cpp 48

Error 2 error C2664: 'CStudent::CStudent(char *,int)' : cannot convert parameter 1 from 'const char *' to 'char *' c:\documents and settings\administrator\桌面\mfc程序\vs2005\vs2005.cpp 48



newfarmerchi 2011-07-13
  • 打赏
  • 举报
回复

#include <iostream>
#include <string>
using namespace std;

class IStudent
{
public:
//virtual ~IStudent() = 0;
virtual const char* GetName() = 0;
virtual int GetAge() = 0;
};

class CStudent : public IStudent
{
public:
CStudent(char *strName, int nAge)
: m_strName(strName)
, m_nAge(nAge)
{
}

virtual ~CStudent()
{
}

virtual const char* GetName()
{
return m_strName.c_str();
}

virtual int GetAge()
{
return m_nAge;
}

private:
string m_strName;
int m_nAge;
};

int main()
{
char *strName = "LiLei";
IStudent *pStudent = new CStudent(strName, 24);
cout << "Name: " << pStudent->GetName() << ", Age: " << pStudent->GetAge() << endl;
delete pStudent;
return 0;
}





downmooner 2011-07-13
  • 打赏
  • 举报
回复
class IStudent
{
public:
virtual ~IStudent() = 0;
virtual const char* GetName() = 0;
virtual int GetAge() = 0;
};

class CStudent : public IStudent
{
public:
CStudent(char *strName, int nAge)
: m_strName(strName)
, m_nAge(nAge)
{
}

virtual ~CStudent()
{
}

virtual const char* GetName()
{
return m_strName.c_str();
}

virtual int GetAge()
{
return m_nAge;
}

private:
string m_strName;
int m_nAge;
};
void main()
{
char *strName = "LiLei";
IStudent *pStudent = new CStudent(strName, 24);
cout << "Name: " << pStudent->GetName() << ", Age: " << pStudent->GetAge() << endl;
delete pStudent;
system("pause");
return;
}
bdmh 2011-07-13
  • 打赏
  • 举报
回复
自己编译一下吧,问题多多
newfarmerchi 2011-07-13
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 mltong2008 的回复:]
作为接口类,这里的虚析构函数不能这样,只能或者

引用 15 楼 newfarmerchi 的回复:

引用 7 楼 mltong2008 的回复:
去掉了虚析构函数,这个是不妥的吧 delete pStudent

引用 3 楼 newfarmerchi 的回复:

C/C++ code

#include <iostream>
#include <string>
us……
[/Quote]


或者以下的解释能对你有所帮助。


摘抄一段《Effective C++》中第14条条款的一部分,
既是对虚析构函数的彻底理解,亦是对纯虚析构函数作用的解释。

在某些类里声明纯虚析构函数很方便。纯虚函数将产生抽象类——
不能实例化的类(即不能创建此类型的对象)。有些时候,
你想使一个类成为抽象类,但刚好又没有任何纯虚函数。怎么办?
因为抽象类是准备被用做基类的,基类必须要有一个虚析构函数,
纯虚函数会产生抽象类,所以方法很简单:在想要成为抽象类的类里声明
一个纯虚析构函数。

这里是一个例子:
class awov {
public:
virtual ~awov() = 0; // 声明一个纯虚析构函数
};

这个类有一个纯虚函数,所以它是抽象的,而且它有一个虚析构函数,
所以不会产生析构函数问题。但这里还有一件事:
必须提供纯虚析构函数的定义:

awov::~awov() {} // 纯虚析构函数的定义

这个定义是必需的,因为虚析构函数工作的方式是:
最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。
这就是说,即使是抽象类,编译器也要产生对~awov的调用,
所以要保证为它提供函数体。如果不这么做,链接器就会检测出来,
最后还是得回去把它添上。



mltong 2011-07-13
  • 打赏
  • 举报
回复
这个是我看到的一个笔试题,我看了后没有找全,借助编译器才……
所以说不要让大家编译。

玄机逸士总体上回答的相当全面。

还有一个问题就是CStudent的构造函数参数是char*,传入的是const char*,这个已经有朋友指出了。

对于编程风格,我觉得这个倒没什么,毕竟string的构造函数也是有const char*类型的。
如果使用的是string*或string&,而调用者有一个字符串指针,还得构造一个string,也有点麻烦。是吧?
[Quote=引用 12 楼 pathuang68 的回复:]

我来说几点:
1. 析构函数绝大部分情况下,不能设为纯虚函数
2. 基类的析构函数,通常情况下都要设为虚函数
3. 既然用了string,为啥又要用char*?在这里根本不需要用char*,编程风格混乱,容易造成错误和部必要的麻烦。
4. 下面这样的写法应该是错误的
C/C++ code

CStudent(char *strName, int nAge)
:……
[/Quote]
mltong 2011-07-13
  • 打赏
  • 举报
回复
作为接口类,这里的虚析构函数不能这样,只能或者[Quote=引用 15 楼 newfarmerchi 的回复:]

引用 7 楼 mltong2008 的回复:
去掉了虚析构函数,这个是不妥的吧 delete pStudent

引用 3 楼 newfarmerchi 的回复:

C/C++ code

#include <iostream>
#include <string>
using namespace std;

class IStudent
{
public:
//vir……
[/Quote]
newfarmerchi 2011-07-13
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 mltong2008 的回复:]
去掉了虚析构函数,这个是不妥的吧 delete pStudent

引用 3 楼 newfarmerchi 的回复:

C/C++ code

#include <iostream>
#include <string>
using namespace std;

class IStudent
{
public:
//virtual ~IStudent() = 0;
vi……
[/Quote]

谢谢指出!

可以这样
class IStudent
{
public:
virtual ~IStudent()= 0;
virtual const char* GetName() = 0;
virtual int GetAge() = 0;
};
IStudent::~IStudent()
{
}
或者直接
class IStudent
{
public:
virtual ~IStudent(){}//= 0;
virtual const char* GetName() = 0;
virtual int GetAge() = 0;
};

64,680

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧