FreeOZ论坛

标题: C++找茬,找出代码中存在的问题 [打印本页]

作者: finger|regnif    时间: 26-1-2012 02:38
标题: C++找茬,找出代码中存在的问题
那试试找出代码的问题,给出你理由。
class X
{
public:
    virtual int SomeFun() = 0{ return 1;}
    void AnotherFun()const
    { 
         v = 100UL;
         printf("%d",v,v);
    }
private:
    unsigned long v;
};
class Y : public X
{
public:
    Y() : p( new int ){}
     ~Y(){ delete p;}
     Y& operator =(Y y)
     {
           *p = *y.p;
     }
private:
    int* p;
};
void Delete(const X* x)
{
    delete x;
}

void Test()
{
    Y* y1 = new Y;
    Y y2 = *y1;
    Delete(y1);
}
作者: 四香油饼    时间: 26-1-2012 14:53
我怎么觉得到处都是问题阿,首先就是看不懂 ,怎么SomeFun后面都没用到过,定义这个纯虚函数有什么意义阿?

v = 100UL; 这句也不理解,我怎么看着像语法错误

AnotherFun() 是个const函数,好像不能访问 v阿 ?

     Y& operator =(Y y)
     {
           *p = *y.p;
     }
这个为啥没有return语句阿?如何返回 Y&的?

void Delete(const X* x)
{
    delete x;
}
这个*x是const的,能被delete吗?不懂

还有Delete(y1)这句,是不是会造成内存泄漏阿?

SomeFun()后面没再定义过,那Y应该也是个虚类了,好像不能生成object,是不是这样啊?

我是c++菜鸟,最怕这种抽象的程序了
作者: finger|regnif    时间: 27-1-2012 00:53
原帖由 四香油饼 于 26-1-2012 12:53 发表
我怎么觉得到处都是问题阿,首先就是看不懂 ,怎么SomeFun后面都没用到过,定义这个纯虚函数有什么意义阿?

v = 100UL; 这句也不理解,我怎么看着像语法错误

AnotherFun() 是个const函数,好像不能访问 v ...


就是有很多问题,所以才让找的。
作者: coredump    时间: 27-1-2012 13:32
  1. class X
  2. {
  3. public:
  4.     //an additional virtual ~X() {} needed here
  5.     virtual int SomeFun() = 0{ return 1;}  //pure virtual function shouldn't contain implementation
  6.     void AnotherFun()const
  7.     {
  8.          v = 100UL; //can't change member value in const method
  9.          printf("%d",v,v); //2 v with 1 '%d'
  10.     }
  11. private:
  12.     unsigned long v;
  13. };
  14. class Y : public X
  15. {
  16. public:
  17.     Y() : p( new int ){}  //p(new int(0))
  18.      ~Y(){ delete p;}
  19.      Y& operator =(Y y) // Y& operator=(const Y& y)  will be much better
  20.      {
  21.            *p = *y.p; // *p = *(y.p), not sure, might not needed, but add () already good code style
  22.            //return *this;
  23.      }
  24. private:
  25.     int* p;
  26. };
  27. void Delete(const X* x)  
  28. {
  29.     delete x; //can't delete const pointer
  30. }

  31. void Test()
  32. {
  33.     Y* y1 = new Y;
  34.     Y y2 = *y1;
  35.     Delete(y1);
  36. }
复制代码

作者: 四香油饼    时间: 27-1-2012 13:58
老乞丐,这一句在Thinking in C++里说是可以这样做的

virtual int SomeFun() = 0{ return 1;}  //pure virtual function shouldn't contain implementation
作者: 四香油饼    时间: 27-1-2012 13:58
这个100UL是个啥表示法阿??谁能帮俺解答一下?
作者: coredump    时间: 27-1-2012 14:54
原帖由 四香油饼 于 27-1-2012 13:58 发表
这个100UL是个啥表示法阿??谁能帮俺解答一下?
100 as unsigned long, 默认情况下100被解释为int
作者: coredump    时间: 27-1-2012 14:56
原帖由 四香油饼 于 27-1-2012 13:58 发表
老乞丐,这一句在Thinking in C++里说是可以这样做的

virtual int SomeFun() = 0{ return 1;}  //pure virtual function shouldn't contain implementation

you are right  

http://stackoverflow.com/questions/2089083/pure-virtual-function-with-implementation
作者: 四香油饼    时间: 27-1-2012 15:59
原帖由 coredump 于 27-1-2012 15:54 发表
100 as unsigned long, 默认情况下100被解释为int


这个是属于C++标准里的么??在教材里从来没见过呢
作者: coredump    时间: 27-1-2012 16:06
原帖由 四香油饼 于 27-1-2012 15:59 发表


这个是属于C++标准里的么??在教材里从来没见过呢

是C的标准用法
http://www.cplusplus.com/doc/tutorial/constants/
作者: tonychangcheng    时间: 27-1-2012 22:26
class X                                                                               //有虚函数的类应该写虚析构函数
{
public:
    virtual int SomeFun() = 0{ return 1;}                      // 纯虚函数没有函数体
    void AnotherFun()const                                       
    {
         v = 100UL;                                                                    // const 不能修改成员
         printf("%d",v,v);                                                       // 应该只有1个参数v, %d是int,v是long,也有问题
    }
private:
    unsigned long v;
};
class Y : public X                                                            // 要override 父类的纯虚函数。 有动态内存分配的,应该写拷贝构造函数和override“=”
{
public:
    Y() : p( new int ){}               
     ~Y(){ delete p;}                                                           // 加上 p = NULL;
     Y& operator =(Y y)
     {
           *p = *y.p;                                                         //            if(NULL == p)  p = new int;            *p = *y.p;           return *this;
     }
private:
    int* p;
};
void Delete(const X* x)                       
{
    delete x;                                                               // 加上 x = NULL;
}

void Test()
{
    Y* y1 = new Y;
    Y y2 = *y1;
    Delete(y1);
}

很好的题目哦~~~  
估计还有没找出来的陷阱。
作者: finger|regnif    时间: 27-1-2012 22:27
老乞丐你那个printf没有答对。。。

还有 pure virtual 可以有实现, 但这不过是小知识而已,没有什么太大实际意义。
作者: MillerYang    时间: 27-1-2012 23:08
先马克。。。回头来学习
作者: dbsdsun    时间: 27-1-2012 23:09
能找出毛病来,能说明什么呢? 感觉像恶作剧
作者: william_m76    时间: 27-1-2012 23:16
class X  必须有虚析构函数,否则 Delete(y1); 会调用~X(),不会调用~Y()。

详细说明如下(书上Copy来的):

// 基类与派生类的析构函数应该为虚,即加virtual 关键字例如
#include <iostream.h>
class Base
{
    public:
        virtual ~Base() { cout<< "~Base" << endl ; }
};

class Derived : public Base
{
    public:
        virtual ~Derived() { cout<< "~Derived" << endl ; }
};

void main(void)
{
    Base * pB = new Derived; // upcast
    delete pB;
}
输出结果为
~Derived
~Base
如果析构函数不为虚 那么输出结果为
~Base

另,coredump是在Brisbane Nokia工作吧? 看到coredump以前写的有关QT的帖子。。。


[ 本帖最后由 william_m76 于 28-1-2012 00:17 编辑 ]
作者: ciasom    时间: 27-1-2012 23:55
我也来凑凑热闹。。

关于virtual的那个同意楼上,貌似在深入C++对象模型里面好像讲过,不过 记不清了。

printf那里面最好用%ld

我觉得最严重的一个问题是,没有定义copy constructor。注意Y y2 = *y1;这个用法,它会调用copy constructor,而不是那个重载的赋值操作符( 在本例中根本用不到它)。 因为copy constructor没有定义,那么编译器生成的那个就会做简单拷贝,就是把y1的p指针赋给个y2的p指针,两个对象的p指向相同的地方。最终可能导致crash。
作者: coredump    时间: 28-1-2012 00:11
原帖由 william_m76 于 27-1-2012 23:16 发表
class Derived : public Base
{
    public:
        virtual ~Derived() { cout<< "~Derived" << endl ; }
};

基类dtor为虚的话,派生类不必指定virtual关键字, 将会自动为virtual, 不过总是在virtual的方法上加上virtual是个好习惯
作者: coredump    时间: 28-1-2012 00:16
原帖由 dbsdsun 于 27-1-2012 23:09 发表
能找出毛病来,能说明什么呢? 感觉像恶作剧
这个例子不规范/错误的地方,的确太多, 而且有些是不应该鼓励去抓的语法陷阱/功能, 而有些是考察的C的语法.

记得哪位大牛说的来着, C++不管用了多久, 总有些你不知道的, 并且在知道了之后会大惊失色的地方, 上面那个油饼提醒我的就是, 从来不知道, 尽管都写了大半辈子的C++了.
作者: coredump    时间: 28-1-2012 00:17
原帖由 ciasom 于 27-1-2012 23:55 发表
printf那里面最好用%ld.

对, gcc的话, 应该最多给个warning, 不会是个error
作者: coredump    时间: 28-1-2012 00:25
原帖由 ciasom 于 27-1-2012 23:55 发表
没有定义copy constructor。注意Y y2 = *y1;这个用法,它会调用copy constructor,而不是那个重载的赋值操作符( 在本例中根本用不到它)。.

这点不同意, copy constructor应该是下面这样的代码才会被调用:

X x1;
X x2(x1);


这个例子中的 Y y2 = *y1;是个明确的赋值.  不过对于允许copy, 尤其是应该deep copy的情况下, 的确应该同时定义operator=和copy ctor. 从这方面说, 没有copy ctor的确算错误.
作者: finger|regnif    时间: 28-1-2012 01:19
原帖由 coredump 于 27-1-2012 22:17 发表

对, gcc的话, 应该最多给个warning, 不会是个error


%ld 还是个warning
作者: finger|regnif    时间: 28-1-2012 01:22
原帖由 coredump 于 27-1-2012 22:25 发表

这点不同意, copy constructor应该是下面这样的代码才会被调用:



这个例子中的 Y y2 = *y1;是个明确的赋值.  不过对于允许copy, 尤其是应该deep copy的情况下, 的确应该同时定义operator=和copy ctor. 从这方 ...


Y y2 = *y1 是copy ctor

[ 本帖最后由 finger|regnif 于 27-1-2012 23:26 编辑 ]
作者: finger|regnif    时间: 28-1-2012 01:48
printf("%d",v,v); 一般 警告级别 开到最高, 以及视警告如错误 的人会知道.

VS我不是太确定, GCC肯定会有警告.

[ 本帖最后由 finger|regnif 于 27-1-2012 23:49 编辑 ]
作者: finger|regnif    时间: 28-1-2012 01:56
原帖由 四香油饼 于 27-1-2012 11:58 发表
老乞丐,这一句在Thinking in C++里说是可以这样做的

virtual int SomeFun() = 0{ return 1;}  //pure virtual function shouldn't contain implementation


这个知道的人比较少. effectiveCpp3rd里也有讲到. 比较偏的东西了. 如果你show给面试官看的话可能会有点效果.

这个在本帖中属于可有可无的问题. 除此之外其它的错误应该是靠谱并实在的.

[ 本帖最后由 finger|regnif 于 27-1-2012 23:59 编辑 ]
作者: finger|regnif    时间: 28-1-2012 02:03
原帖由 dbsdsun 于 27-1-2012 21:09 发表
能找出毛病来,能说明什么呢? 感觉像恶作剧


这个virtual int SomeFun() = 0{ return 1;}的确有点恶作剧. 其它的都很实在.

真正的恶作剧是这种: i++++i++i
作者: coredump    时间: 28-1-2012 02:35
原帖由 finger|regnif 于 28-1-2012 01:22 发表


Y y2 = *y1 是copy ctor

临睡觉前,特意验证了下
  1. #include

  2. using namespace std;


  3. class X
  4. {
  5. public:
  6.    X& operator=(const X& other)
  7.    {
  8.       cout << "operator= called";
  9.       return *this;
  10.    }
  11.    X() {}
  12.    X(const X& other) {
  13.       cout << "copy ctor called";
  14.    }
  15. };
  16. int main() {
  17.    X x1, x2;
  18.    x1 = x2; //output: operator= called
  19.   X x3(x1); //output:copy ctor called
  20.    return 0;
  21. }
复制代码

作者: coredump    时间: 28-1-2012 02:42
原帖由 finger|regnif 于 28-1-2012 02:03 发表


这个virtual int SomeFun() = 0{ return 1;}的确有点恶作剧. 其它的都很实在.

真正的恶作剧是这种: i++++i++i

后一种很孔乙己, 我如果面试人, 最标准的答案不是给出正确结果, 而是拒绝回答, 然后给出拒绝的理由就行.
用人做compiler的活, 不是自虐狂就是神经病, 谁写这样的代码, 被review的时候, 肯定被骂得狗血淋头
作者: finger|regnif    时间: 28-1-2012 10:15
原帖由 coredump 于 28-1-2012 00:35 发表
......
X x1, x2;
x1 = x2; //output: operator= called



X x2;
X x1 = x2;


是不同的. 前一个是赋值, 后一个是copy ctor. 这也算是copy ctor和operator=要同时存在的其中一个原因.

实际开发中见过几个用 X x1=x2;然后只定义operator=不定义copy ctor, 然后出bug的. 所以做为一个茬放在这里.
作者: coredump    时间: 28-1-2012 10:17
原帖由 finger|regnif 于 28-1-2012 10:15 发表





是不同的. 前一个是赋值, 后一个是copy ctor. 这也算是copy ctor和operator=要同时存在的其中一个原因.

实际开发中见过几个用 X x1=x2;然后只定义operator=不定义copy ctor, 然后出bug的. 所以做为一 ...
对啦, 是我没仔细看,谢谢指出
作者: finger|regnif    时间: 28-1-2012 10:34
原帖由 coredump 于 28-1-2012 00:42 发表

后一种很孔乙己, 我如果面试人, 最标准的答案不是给出正确结果, 而是拒绝回答, 然后给出拒绝的理由就行.
用人做compiler的活, 不是自虐狂就是神经病, 谁写这样的代码, 被review的时候, 肯定被骂得狗血淋头


刚毕业的时候还真做过 i++++i 这种题目. 我也认为 拒绝回答 是最好的答案. 其实对这种类似的语句, 很可能是未定义行为, 不同编译器实现不一样, 没有sequence point没有答案, .
作者: 四香油饼    时间: 28-1-2012 10:36
俺来仰视一下楼上的各位牛人们
作者: 四香油饼    时间: 2-2-2012 14:45
楼主你给个标准答案阿,我还等着学习呢
作者: finger|regnif    时间: 2-2-2012 23:03
原帖由 四香油饼 于 2-2-2012 12:45 发表
楼主你给个标准答案阿,我还等着学习呢


unsigned long 的格式串是%lu. %d和%ld都可能出现负数, 当v过大时.  -Wformat -Werror的同学可能会知道.

其它的问题大家该说的都说了.




欢迎光临 FreeOZ论坛 (https://www.freeoz.org/ibbs/) Powered by Discuz! X3.2