zoukankan      html  css  js  c++  java
  • C++可以做好而C做不好的事情

    导读

    现在好多C++软件工程师,大多数都是C语言出身,他们在工作过程中用得更多的还是C语言思想,或许他们还没有意识到C++ 的一些更加有趣的特性。现在给大家解释什么事情是C++可以做好,而C做不好的。希望对这一类人有一点点启发。

    目录

    1. 第一次尝试
    2. 改进
    3. 另一种改进
    4. 不用类来改进

    正文

    1、第一次尝试

    现在给定一个例子:

    #include <stdio.h>
    class Trace{
    public:
    	void print( char *s ){ printf("%s", s); }
    };
    int main(){
    	Trace t;
    	t.print("begin main
    ");
    	t.print("end main
    ");
    }
    

    2、改进

    如果能够在必要时关闭跟踪输出(trace output,这将会是个有用的功能。现在改一下类的定义就行:

    #include <stdio.h>
    class Trace{
    public:
    	Trace(){ noisy = 0; }
    	void print( char *s ){ if (noisy)  printf("%s", s); }
    	void on() { noisy = 1; }
    	void off() { noisy = 0; }
    private:
    	int noisy;
    };
    

    此时类定义包括两个公有成员函数onoff,它们影响私有成员noisy的状态。只有noisyon(非零)才可以输出。因此,

    t.off();
    

    会关闭t的对外输出,直到我们通过下面的语句恢复t的输出能力:

    t.on();
    

    由于这些成员函数定义在Trace类自身的定义内,C++会内联(inline)扩展它们,所以就使得即使在不进行跟踪的情况下,在程序中保留Trace对象也不必付出许多代价。只要让print函数不做任何事情,然后重新编译程序,就可以有效地关闭所有Trace对象的输出。

    3、另一种改进

    如果让它打印到标准输出设备以外的东西上,那又该怎么改进呢?一种方法是可以用继承来创建一种新的Trace类,但是为了尽量让示例简单,避免介绍新的概念。现在作如下改进:

    #include <stdio.h>
    class Trace{
    public:
    	Trace(){ noisy = 0; f = stdout; }
    	Trace(FILE* ff){ noisy = 0; f = ff; }
    	void print( char *s ){ if (noisy) fprintf(f, "%s", s); }
    	void on() { noisy = 1; }
    	void off() { noisy = 0; }
    private:
    	int noisy;
    	FILE* f;
    };
    

    这样的改动基于一个事实:

    printf(args);
    

    等价于:

    fprintf(stdout, args);
    

    创建一个没有特殊要求的Trace类,则其对象的成员fstdout。因此,调用fprintf所做的工作与调用前一个版本的printf是一样的。

    Trace有两个构造函数:一个是无参的构造函数,输出到stdout,另一个是带参构造函数,允许明确指定输出文件。因此,上面那个使用了Trace类的示例程序可以继续工作,但也可

    以将输出定向到比如说stderr上:

    int main(){
    	Trace t(stderr);
    	t.print("begin main
    ");
    	t.print("end main
    ");
    }
    

    简而言之,运用C++类的特殊方式,使得对程序的改进变得轻而易举,而不会影响使用这些类的代码。

    4、不用类来实现

    对于这个问题,典型的C解决方案会怎么样的。

    #include <stdio.h>
    static int noisy = 1;
    void trace(char *s)
    {
    	if(noisy)
    		printf("%s
    ", s);
    }
    
    void trace_on(){ noisy = 1; }
    void trace_off(){ noisy = 0;}
    

    这个方法是有效的,但是与C++方法比较起来,有3个明显的缺点。

    1. 函数trace不是内联,因此即使当跟踪关闭时,它还保持着函数调用的开销。

    2. C版本引入了3个全局名字:tracetrace_ontrace_off,而C++只引入了1个。

    3. 很难将这个例子一般化,使之能输出到一个以上的文件中。为什么这么说呢?考虑一下我们会怎么样使用这个trace函数:

    int main(){
    	trace("begin main
    ");
    	// main函数主体
    	trace ("end main
    ");
    }
    

    采用C++,可以只在创建Trace对象时一次性指定文件名。而在C版本中,情况相反,没有合适的位置指定文件名。一个显而易见的办法就是给函数trace 增加一个参数,但是需要找到所有对trace函数的调用,并插入这个新增的参数。另一种办法就是引入名为trace_out的第4个函数,用来将跟踪输出转向到其他文件。这当然也得要求判断和记录跟踪输出是打开还是关闭。考虑一下,譬如,main调用的一个函数恰好利用了trace_out向另一个文件输出,则何时切换输出的开关状态呢?显然,要想使结果正确需要花费相当的精力。

  • 相关阅读:
    windows 程序设计的一些总结
    Ubuntu 16.04 LTS 安装开发工具
    C++ 虚函数表
    day 14 函数的嵌套,作用域
    命名空间(名称空间)
    day15编码
    day16迭代器
    day5
    day4
    day3
  • 原文地址:https://www.cnblogs.com/iyoyos/p/4284917.html
Copyright © 2011-2022 走看看