一公司笔试题
1. 请仔细阅读下面的资料:
材料一:CArray
template< class TYPE, class ARG_TYPE > class CArray : public CObject
Parameters:
TYPE
Template parameter specifying the type of objects stored in the array.
TYPE is a parameter that is returned by CArray.
ARG_TYPE
Template parameter specifying the argument type used to access objects stored in the array.
Often a reference to TYPE. ARG_TYPE is a parameter that is passed to CArray.
Remarks:
The CArray class supports arrays that are are similar to C arrays, but can dynamically shrink and grow as necessary.
Array indexes always start at position 0. You can decide whether to fix the upper bound or allow the array to expand when you add elements past the current bound. Memory is allocated contiguously to the upper bound, even if some elements are null.
int CArray::Add (ARG_TYPE newElement);
Return Value:
The index of the added element.
Parameters:
ARG_TYPE
Template parameter specifying the type of arguments referencing elements in this array.
newElement
The element to be added to this array.
TYPE& CArray::operator [] (int nIndex);
Parameters:
TYPE
Template parameter specifying the type of elements in this array.
nIndex
Index of the element to be accessed.
Remarks:
Returns the array reference of element at the specified index.
1) 材料二:CList
template<class TYPE, class ARG_TYPE>class CList : public CObject
Parameters:
TYPE
Type of object stored in the list.
ARG_TYPE
Type used to reference objects stored in the list. Can be a reference.
Remarks:
The CList class supports ordered lists of nonunique objects accessible sequentially or by value.
CList lists behave like doubly-linked lists.
void CList::AddTail(ARG_TYPE newElement);
Parameters:
ARG_TYPE
Template parameter specifying the type of the list element (can be a reference).
newElement
The element to be added to this list.
Remarks:
Adds a new element or list of elements to the tail of this list. The list can be empty before the operation.
2) 材料三: realloc
realloc
Reallocate memory blocks.
void *realloc(void *memblock, size_t size);
Return Value:
The return value points to a storage space that is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.
Remarks:
The size argument gives the new size of the block, in bytes. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block can be in a different location. Because the new block can be in a new memory location, the pointer returned by realloc is not guaranteed to be the pointer passed through the memblock argument.
3) 请指出下面这段代码可能会出现的问题
CList<VARIANT*, VARIANT*> g_ValueList;
CArray<VARIANT, const VARIANT&> g_ValuePool;
void AddNewValue (const VARIANT& newValue)
{
g_ValueList.AddTail(&g_ValuePool[g_ValuePool.Add(newValue)]);
}
4. 阅读以下程序,纠正其中的错误。(40分钟)
//------------------------------------------------------------------
class CCelsius
{
public:
CCelsius() { m_nC = 0; }
~CCelsius() {}
short ToFahrenheit() { return m_nC * 9 / 5 + 32; }
void SetC(short nCelsius) { m_nC = nCelsius; }
short GetC() { return m_nC; }
protected:
short m_nC;
};
class CFahrenheit
{
public:
CFahrenheit() { m_nF = 0; }
~CFahrenheit() {}
short ToCelsius() { return (m_nF - 32) * 5 / 9; }
void SetF(short nFahrenheit) { m_nF = nFahrenheit; }
short GetF() { return m_nF; }
protected:
short m_nF;
};
class CTemperature : public CCelsius , public CFahrenheit
{
public:
CTemperature();
~CTemperature();
BOOL CreateLevel(UINT nSize);
void ReleaseLevel();
UINT GetLevel(int nCelsius);
protected:
UINT m_nSize;
short* m_pLevel;
};
//------------------------------------------------------------------
CTemperature::CTemperature()
{
m_nSize = 0;
m_pLevel = NULL;
}
CTemperature::~CTemperature()
{
ReleaseLevel();
}
BOOL CTemperature::CreateLevel(UINT nSize)
{
ASSERT(m_pLevel == NULL);
if (m_pLevel)
return FALSE;
m_pLevel = new short[nSize];
if (m_pLevel == NULL)
return FALSE;
for (UINT i = 0; i < nSize; i++)
m_pLevel[i] = 100 * i * i;
m_nSize = nSize;
return TRUE;
}
void CTemperature::ReleaseLevel()
{
if (m_pLevel)
{
delete [] m_pLevel;
m_nSize = 0;
m_pLevel = NULL;
}
}
UINT CTemperature::GetLevel(int nT)
{
ASSERT(m_pLevel);
for (UINT nLevel = 0; nLevel < m_nSize; nLevel++)
{
if (m_pLevel[nLevel] > nT)
break;
}
return nLevel;
}
void OutC(CCelsius* pC)
{
if (pC)
printf("摄氏%d度等于华氏%d度\n", pC->GetC(), pC->ToFahrenheit());
}
void OutF(CFahrenheit* pF)
{
if (pF)
printf("华氏%d度等于摄氏%d度\n", pF->GetF(), pF->ToCelsius());
}
void OutL(CTemperature* pT)
{
if (pT)
{
printf("摄氏%d度的等级为:%d\n", pT->GetC(), pT->GetLevel(pT->GetC()));
printf("华氏%d度的等级为:%d\n", pT->GetF(), pT->GetLevel(pT->GetF()));
}
}
void main()
{
CTemperature* pTemperature = new CTemperature;
if (pTemperature == NULL)
return;
CCelsius* pCelsius = (CCelsius*)pTemperature;
pCelsius->SetC(100);
OutC(pCelsius);
CFahrenheit* pFahrenheit = (CFahrenheit*)pCelsius;
pFahrenheit->SetF(400);
OutF(pFahrenheit);
pTemperature->CreateLevel(3);
OutL(pTemperature);
CTemperature* pTempOther = new CTemperature;
if (pTempOther == NULL)
return;
*pTempOther = *pTemperature;
delete pFahrenheit;
OutL(pTempOther);
delete pTempOther;
}
5. C++程序设计
1) 写出以下程序的运行结果:
#include <iostream>
class Base
{
public:
Base()
{
cout << "Base()" << endl;
}
Base(const Base &theBase)
{
cout << "Base(const Base &theBase)" << endl;
}
~Base()
{
cout << "~Base()" << endl;
}
void Open()
{
OnOpen();
}
private:
virtual void OnOpen() = 0;
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived()" << endl;
}
Derived(const Derived &theDerived)
{
cout << "Derived(const Derived &theDerived)" << endl;
}
~Derived()
{
cout << "~Derived()" << endl;
}
private:
virtual void OnOpen()
{
//这里可能抛出异常
}
};
Base *CreateInstance()
{
return new Derived();
}
int main()
{
Base *pBase = ::CreateInstance();
if (pBase)
{
pBase->Open();
delete pBase;
}
return 0;
}
2) 在1)中,类Base和类Derived的实现有没有问题?如果有,如何修改?
3) 说明1)中类Base的Open函数和OnOpen函数的设计目的和意义。
4) 使用STL技术修改main()函数中的代码,使之成为异常安全的。
问题点数:50、回复次数:23Top
1 楼vcpb(yeah)回复于 2005-12-22 20:43:23 得分 0
你敲进去的么,强Top
2 楼sankt(做最好的自己)回复于 2005-12-22 20:50:33 得分 0
5.我来回到第五题
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base()" << endl;
}
Base(const Base &theBase)
{
cout << "Base(const Base &theBase)" << endl;
}
virtual ~Base()
{
cout << "~Base()" << endl;
}
void Open()
{
OnOpen();
}
private:
virtual void OnOpen() = 0;
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived()" << endl;
}
Derived(const Derived &theDerived)
{
cout << "Derived(const Derived &theDerived)" << endl;
}
virtual ~Derived()
{
cout << "~Derived()" << endl;
}
private:
virtual void OnOpen()
{
//这里可能抛出异常
}
};
Base *CreateInstance()
{
return new Derived();
}
int main()
{
Base *pBase = ::CreateInstance();
if (pBase)
{
pBase->Open();
delete pBase;
}
system("pause");
return 0;
}Top
3 楼sankt(做最好的自己)回复于 2005-12-22 20:55:58 得分 0
1)中输出
Base()
Derived()
~Base()
2)在1)中,类Base和类Derived的实现有没有问题?如果有,如何修改?
修改如上面的程序
析构函数必须是virtual的.
多态的实现于访问控制的修饰符没有关系。
3)说明1)中类Base的Open函数和OnOpen函数的设计目的和意义。
更好的实现了面向接口编程
4) 使用STL技术修改main()函数中的代码,使之成为异常安全的。
//======
Top
4 楼sankt(做最好的自己)回复于 2005-12-22 20:58:29 得分 0
题目不错,我要好好想想
Top
5 楼manplus(魅力加加)回复于 2005-12-22 23:15:32 得分 0
markTop
6 楼Mr_Yang(初级程序员)回复于 2005-12-22 23:23:23 得分 0
markTop
7 楼iamcaicainiao(老菜 ◆无为莫千钧●恨水梦少白▼)回复于 2005-12-23 07:54:27 得分 0
我靠,这哪个公司的,像我英文这么菜的。呵呵。抽空再慢慢研究Top
8 楼fine10000(好心情)回复于 2005-12-23 08:27:07 得分 0
学习.Top
9 楼xiaonian_3654(你猜猜(我要打光棍,小乔嫁不了))回复于 2005-12-23 08:53:22 得分 0
CList<VARIANT*, VARIANT*> g_ValueList;
CArray<VARIANT, const VARIANT&> g_ValuePool;
void AddNewValue (const VARIANT& newValue)
{
g_ValueList.AddTail(&g_ValuePool[g_ValuePool.Add(newValue)]);
}
=================================================================
这个应该是楼主写反了, 这个程序是没有问题的,因为CList里面存的是指针,
g_ValuePool[g_ValuePool.Add(newValue)]返回的是引用, 是g_ValuePool里面
的内容的引用,
&g_ValuePool[g_ValuePool.Add(newValue)是g_ValuePool内容的地址
如果
CArray<VARIANT, const VARIANT&> g_ValuePool;
改成
CArray<VARIANT, const VARIANT> g_ValuePool;
g_ValuePool[g_ValuePool.Add(newValue)]返回的是临时变量,
&g_ValuePool[g_ValuePool.Add(newValue)]就是临时变量的地址,
这就错了,
我想应该是这个样子吧,
Top
10 楼chengzanmiao(高薪為共產當多納稅)回复于 2005-12-23 09:16:47 得分 0
markTop
11 楼MarcoCC(成长与不断的跌倒和失败)回复于 2005-12-23 09:35:44 得分 0
大致看了下第四题:
void main()
{
CTemperature* pTemperature = new CTemperature;
if (pTemperature == NULL)
return;
CCelsius* pCelsius = (CCelsius*)pTemperature;
pCelsius->SetC(100);
OutC(pCelsius);
CFahrenheit* pFahrenheit = (CFahrenheit*)pCelsius; //这个类型转换是不安全的
pFahrenheit->SetF(400);
OutF(pFahrenheit);
pTemperature->CreateLevel(3);
OutL(pTemperature);
CTemperature* pTempOther = new CTemperature;
if (pTempOther == NULL)
return;
*pTempOther = *pTemperature; //这将导致两个指针指向同一块new出来的内存区
delete pFahrenheit;
OutL(pTempOther);
delete pTempOther; //重复delete同一块new出来的内存区,异常
//此外pTemperature原指向的那块new的内存泄漏
}Top
12 楼lj197912(从零开始)回复于 2005-12-23 09:51:21 得分 0
CList<VARIANT*, VARIANT*> g_ValueList;
CArray<VARIANT, const VARIANT&> g_ValuePool;
void AddNewValue (const VARIANT& newValue)
{
g_ValueList.AddTail(&g_ValuePool[g_ValuePool.Add(newValue)]);
}
=========================
我觉得问题是因为CList元素的类型是VARIANT*所以有可能造成,g_ValuePool元素修改会令g_ValueList的元素也跟着改变.而且有可能内存泄漏。g_ValueList析构掉会引起g_ValuePool内容的释放Top
13 楼xiaonian_3654(你猜猜(我要打光棍,小乔嫁不了))回复于 2005-12-23 10:11:22 得分 0
g_ValueList析构掉会引起g_ValuePool内容的释放
====================================
开玩笑,Top
14 楼iamcaicainiao(老菜 ◆无为莫千钧●恨水梦少白▼)回复于 2005-12-23 10:12:32 得分 0
to sankt(黄景天)
你的输出结果肯定有问题吧。drived既然构造了,就不惜购了?Top
15 楼xiaonian_3654(你猜猜(我要打光棍,小乔嫁不了))回复于 2005-12-23 10:22:41 得分 0
CList<VARIANT*, VARIANT*> g_ValueList;
CArray<VARIANT, const VARIANT&> g_ValuePool;
void AddNewValue (const VARIANT& newValue)
{
g_ValueList.AddTail(&g_ValuePool[g_ValuePool.Add(newValue)]);
}
===========================================================
我想错了, 这个代码的问题是:
如果当CArray添加元素的时候, 可能会重新申请内存, 这个时候CList里面的指针会失效
如果CArray使用ralloc的申请策略,在ralloc成功的情况下不会有问题Top
16 楼HuangQQ(黄QQ)回复于 2005-12-23 10:25:24 得分 0
先寒一个。。。。。。
啥公司的面试题,这么恐怖??Top
17 楼ericqxg007(还有很多东西要学(卡卡一米阳光))回复于 2005-12-23 11:12:18 得分 0
markTop
18 楼fflush(stdin)回复于 2005-12-23 11:16:23 得分 0
我想错了, 这个代码的问题是:
如果当CArray添加元素的时候, 可能会重新申请内存, 这个时候CList里面的指针会失效
如果CArray使用ralloc的申请策略,在ralloc成功的情况下不会有问题
---------------------------------------------
realloc成功的情况下,整个内存块也有可能被转移到新的地方,所以也是有问题的Top
19 楼MarcoCC(成长与不断的跌倒和失败)回复于 2005-12-23 11:59:21 得分 0
to sankt(黄景天)
你的输出结果肯定有问题吧。drived既然构造了,就不惜购了?
sankt(黄景天)的结果是正确的,由于没有声明成虚析构,当Base析构时不会去调用derived的析构函数。
Top
20 楼luvybird()回复于 2005-12-23 13:18:47 得分 0
markTop
21 楼corrupt(喜欢 睡在床板下 的思考)回复于 2005-12-23 14:29:54 得分 0
这个公司 还是 不错的Top
22 楼lj197912(从零开始)回复于 2005-12-23 16:17:51 得分 0
CList<VARIANT*, VARIANT*> g_ValueList;
CArray<VARIANT, const VARIANT&> g_ValuePool;
void AddNewValue (const VARIANT& newValue)
{
g_ValueList.AddTail(&g_ValuePool[g_ValuePool.Add(newValue)]);
}
=====================
g_ValueList 的VARIANT*内存如何管理?如果delete 的话,会出现什么情况?Top
23 楼GGeneral2(阿弥陀佛)回复于 2005-12-26 00:49:41 得分 0
大难!大难!Top