随笔 - 181  文章 - 15  trackbacks - 0
<2008年12月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

常用链接

留言簿(1)

随笔分类

随笔档案

My Tech blog

搜索

  •  

最新评论

阅读排行榜

评论排行榜

在这一部分之前,书中介绍了基本类型的显式初始化以及简单的异常处理.
基本类型的显式初始化是比较简单的.就是说你在定义一个整型变量的时候,有两种不同的情况:
int i1;         // undefined value
int i2 = int(); // initialized with zero

如果按照前一种,会作"值未定义;如果按照后一种,则自动被初始化为0.这样也就确保了你的类在初始化的时候有一个确定的初始值.
至于异常的处理等问题,书中会在后面有比较详细的描述.这里可以看到比较有意思的一点,就是指定函数抛出的异常类型,这于Java很像:
void f() throw(bad_alloc);
下面转入正题:命名空间.
有了命名空间,它将会取代函数和类作用于全局,并作为它所统领的那些类和函数的唯一标识存在.这样可以避免命名冲突情况的出现.正如书中所说:
Unlike classes, namespaces are open for definitions and extensions in different modules. Thus
you can use namespaces to define modules, libraries, or components even by using multiple
files. A namespace defines logical modules instead of physical modules (in UML and other
modeling notations, a module is also called a package).

可以像这样定义一个命名空间:
namespace MyNameSpace
{
    
class MyClass
    {
        
private:
        
char * _classInfo;
        
public:
        
char* getClassInfo()
        {
            
return _classInfo;
        }
        MyClass(
const char* info)
        {
            _classInfo
=new char[strlen(info)];
            strcpy(_classInfo,info);
        }
        
~MyClass()
        {
            
if(_classInfo)
            {
                std::cout
<<"free classinfo";
                delete[] _classInfo;
            }
        }
    };
    
void printMyClassInfo(MyClass &instance)
    {
        std::cout
<<instance.getClassInfo();
    }
}
从上面可以看出,这个命名空间里面包括了一个类和一个函数.类中包含了char*类型的成员变量.函数printMyClassInfo 以一个MyClass类型的引用作为参数.为什么要用引用呢?熟悉c++的人应当很清楚,我是通过实验才刚刚知道原因.这个原因我将会在后面说明.
好现在来看一下调用过程,通常的调用过程是这样的:
int main()
{
    MyNameSpace::MyClass instance(
"MyClass!\n");
    MyNameSpace::printMyClassInfo(instance);
}
这没有任何问题,但有意思的是,还可以这样调用:
int main()
{
    MyNameSpace::MyClass instance(
"MyClass!\n");
    printMyClassInfo(instance);
}
看来c++中在使用一个命名空间的类或者函数的时候,这个命名空间就被"自动"引入了.当寻找函数printMyClassInfo的时候会在当前的上下文中进行寻找的同时,还会到以前用到过的命名空间中去寻找.
当然,通常情况下我们喜欢这样做:
using namespace MyNameSpace; 
int main()
{
    MyClass instance(
"MyClass!\n");
    printMyClassInfo(instance);

}
但是并不是在任何情况下都鼓励using namespace这种做法的.在书中将得比较清楚:
Note that you should never use a using directive when the context is not clear (such as in header
files, modules, or libraries). The directive might change the scope of identifiers of a namespace,
so you might get different behavior than the one expected because you included or used your
code in another module. In fact, using directives in header files is really bad design.

上面这段话强调了当上下文并不明确的情况下(比如在一个头文件,组件或者库里面),不要使用using这种写法,这个指令会改变命名空间标识符的作用域,这样你就有可能引发和你预期不相同的行为,因为你会在另外一个组件中引用你的代码或使用它.事实上,将using标识符写在头文件里面是一种相当不好的设计.
在这里,我看了一下c++程序设计语言这本书,发现命名空间除了像上面这样声明以外,还可以像类一样这样来写:
在命名空间中这样定义
void printMyClassInfo(MyClass &);
然后在外面写函数的主体
void MyNameSpace::printMyClassInfo(MyClass &instance)
{
    std::cout
<<instance.getClassInfo();
}
好了,写了这么多,再来看看刚才留下来的那个问题.
其实很简单,一个函数如果传递的是值,那么就会在内存中产生一个一模一样的"复本",而那个字符指针也会被复制一次.当传送的值超过它的作用域的时候 ,就会被释放掉,而被复制的"本体"在程序运行结束之后,又会被"释放一次".这样在运行的时候,它会提示你这样的错误:
*** glibc detected *** double free or corruption (fasttop): 0x0804a008 ***

在我们的MyClassl类的析构中,我们有一个输出,所以这里就输出了两次:
free classinfofree classinfo




posted on 2007-06-14 22:06 littlegai 阅读(275) 评论(0)  编辑 收藏 引用 所属分类: 我的读书笔记

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理