油库7号

Last Day Of The Summer
 
油库7号 @ 2010-04-26 10:21





 
油库7号 @ 2010-04-26 10:13








 
油库7号 @ 2010-04-07 22:31

“成败就在瞬息之间。但无论今后怎样,毕竟我们曾经成功过。”
——王江民
 



 
油库7号 @ 2010-03-21 19:03






 
健一 @ 2010-03-05 17:59







 
健一 @ 2009-12-24 19:20







 
ajk @ 2009-11-18 14:12

容易令人迷惑的构造函数
 
5、使用explicit禁止隐式类型转换
在构造函数的前面加上explicit就可以避免构造函数被自动匹配为转换构造函数,从而避免了隐式类型转换。
比较下面两个例子:
#define _CRT_SECURE_NO_DEPRECATE 1
//design by ajk
#include    <iostream>
using namespace::std;
 
class Student{
public:
    Student(char const *ptrName = "", int id = 0):m_id(id){
        ptrName = ptrName ? ptrName:"";
        m_sPtrName = new char[strlen(ptrName)+1];
        strcpy(m_sPtrName, ptrName);
        cout << "Constructing NEW student "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
    }
 
    Student(Student const &s){
        char *prefix = "COPY OF ";
        size_t length = strlen(s.m_sPtrName) + strlen(prefix) + 1;
        m_sPtrName = new char[length];
        strcpy(m_sPtrName, prefix);
        strcat(m_sPtrName, s.m_sPtrName);
        m_id = s.m_id;
        cout << "Constructing student "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
    }
 
    ~Student(){
        cout << "Destructing the student "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
        delete []m_sPtrName;
    }
 
    Student& operator=(Student const &s){
        char *prefix = "ASSIGNED FROM ";
        size_t length = strlen(s.m_sPtrName) + strlen(prefix) + 1;
        if(length != strlen(m_sPtrName)+1){
            delete []m_sPtrName;
            m_sPtrName = new char[length];
        }
        strcpy(m_sPtrName, prefix);
        strcat(m_sPtrName, s.m_sPtrName);
        m_id = s.m_id;
        cout << "Assigned the student "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
        return *this;
    }
 
    void GetInfo(){
        cout << "Get Info: The Student is "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
    }
private:
    char *m_sPtrName;
    int m_id;
};
 
Student Func(Student s){
    cout << "In the Func()" << endl;
    s.GetInfo();
    cout << "Leaving the Func()" << endl;
    return s;
}
 
int main(){
    Student s1("ajk", 1);
    s1 = "Tony";
    cout << "Back in main()" << endl;
}
在这个例子中,构造函数没有加explicit属性,所以”Tony”这个字符串会自动去匹配转换构造函数,实现隐式转换。
输出结果为:
Constructing NEW student ajk, id is 1
Constructing NEW student Tony, id is 0
Assigned the student ASSIGNED FROM Tony, id is 0
Destructing the student Tony, id is 0
Back in main()
Destructing the student ASSIGNED FROM Tony, id is 0
 
下面的例子中,在构造函数加上了的explicit
#define _CRT_SECURE_NO_DEPRECATE 1
//design by ajk
#include    <iostream>
using namespace::std;
 
class Student{
public:
    explicit Student(char const *ptrName = "", int id = 0):m_id(id){
        ptrName = ptrName ? ptrName:"";
        m_sPtrName = new char[strlen(ptrName)+1];
        strcpy(m_sPtrName, ptrName);
        cout << "Constructing NEW student "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
    }
 
    Student(Student const &s){
        char *prefix = "COPY OF ";
        size_t length = strlen(s.m_sPtrName) + strlen(prefix) + 1;
        m_sPtrName = new char[length];
        strcpy(m_sPtrName, prefix);
        strcat(m_sPtrName, s.m_sPtrName);
        m_id = s.m_id;
        cout << "Constructing student "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
    }
 
    ~Student(){
        cout << "Destructing the student "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
        delete []m_sPtrName;
    }
 
    Student& operator=(Student const &s){
        char *prefix = "ASSIGNED FROM ";
        size_t length = strlen(s.m_sPtrName) + strlen(prefix) + 1;
        if(length != strlen(m_sPtrName)+1){
            delete []m_sPtrName;
            m_sPtrName = new char[length];
        }
        strcpy(m_sPtrName, prefix);
        strcat(m_sPtrName, s.m_sPtrName);
        m_id = s.m_id;
        cout << "Assigned the student "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
        return *this;
    }
 
    void GetInfo(){
        cout << "Get Info: The Student is "
            << m_sPtrName
            << ", id is "
            << m_id << endl;
    }
private:
    char *m_sPtrName;
    int m_id;
};
 
Student Func(Student s){
    cout << "In the Func()" << endl;
    s.GetInfo();
    cout << "Leaving the Func()" << endl;
    return s;
}
 
int main(){
    Student s1("ajk", 1);
    s1 = "Tony";     //Error,由于有explicit,所以不能进行隐式转换
    cout << "Back in main()" << endl;
}
构造函数被加上explicit属性后,就不能被自动匹配为转换构造函数,所以这里的字符串”Tony”不能进行隐式类型转换。类型不匹配导致编译不能通过。



 
ajk @ 2009-11-18 14:10

容易令人迷惑的构造函数
 
4、什么时候会产生无名对象
(1)独立的显式调用构造函数时。
int main(){
    Student("ajk", 1);
    cout << "Back in main()" << endl;
}
输出结果为:
Constructing NEW student ajk, id is 1
Destructing the student ajk, id is 1
Back in main()
 
(2)显式调用构造函数(含拷贝构造函数)为一个已有对象赋值时。
int main(){
    Student s;
    s = Student("ajk", 1);
    cout << "Back in main()" << endl;
}
输出结果为:
Constructing NEW student , id is 0
Constructing NEW student ajk, id is 1
Assigned the student ASSIGNED FROM ajk, id is 1
Destructing the student ajk, id is 1
Back in main()
Destructing the student ASSIGNED FROM ajk, id is 1
 
在上面的例子中,名字s是已经存在的一个对象的名字,所以在赋值时新创建的对象就是一个“无名对象”,它的生命期仅维持在创建它的这条语句上,一离开这条语句就被析构。
再看一个使用拷贝构造函数的例子:
int main(){
    Student s;
    Student s1("ajk", 1);
    s = Student(s1);
    cout << "Back in main()" << endl;
}
    输出结果为
Constructing NEW student , id is 0
Constructing NEW student ajk, id is 1
Constructing student COPY OF ajk, id is 1
Assigned the student ASSIGNED FROM COPY OF ajk, id is 1
Destructing the student COPY OF ajk, id is 1
Back in main()
Destructing the student ajk, id is 1
Destructing the student ASSIGNED FROM COPY OF ajk, id is 1
 
 
在这个地方要特别注意把赋值跟初始化区别开来。如果是初始化情况就不一样了。
比如:
int main(){
    Student s = Student("ajk", 1);
    cout << "Back in main()" << endl;
}
   
int main(){
    Student &s = Student("ajk", 1);
    cout << "Back in main()" << endl;
}
 
这两种情况都是初始化,输出结果为:
Constructing NEW student ajk, id is 1
Back in main()
Destructing the student ajk, id is 1
 
对于Student s = Student("ajk", 1)新创建对象的名字为s。有名字。
对于Student &s = Student("ajk", 1)新创建对象的别名是s。同样有名字。
所以他们的的生命期都要持续到main()函数结束。
 
(3)显式调用构造函数(含拷贝构造函数),并取其地址去初始化或赋值给指针。
int main(){
    Student *s = &Student("ajk", 1);
    s->GetInfo();
    cout << "Back in main()" << endl;
}
输出结果为:
Constructing NEW student ajk, id is 1
Destructing the student ajk, id is 1
Get Info: The Student is 葺葺葺葺[1], id is 1
Back in main()
要注意,这种情况是非常危险的。
显式调用了构造函数,意味着这里会创建一个对象,但是此对象是一个“无名对象”。因为指针不同于引用,它只接收地址而不会成为初始化它的对象的别名。
创建了“无名对象”后,将其地址送给指针s。随着这条语句的结束,此“无名对象”的生命也到尽头,被析构。意味着指针s指向的空间被释放掉。所以后面在调用s->GetInfo()时,必然导致结果不正确。
类似的,再看一个拷贝构造函数的例子:
int main(){
    Student s1("ajk", 1);
    Student *s = &Student(s1);
    s->GetInfo();
    cout << "Back in main()" << endl;
}
输出结果如下:
Constructing NEW student ajk, id is 1
Constructing student COPY OF ajk, id is 1
Destructing the student COPY OF ajk, id is 1
Get Info: The Student is 葺葺葺葺葺葺葺葺, id is 1
Back in main()
Destructing the student ajk, id is 1



 
Locations of visitors to this page
日历
网志分类
『所有网志』
『汇编语言』
『C++』
『网络编程简介』
『 Win32程序设计』
『不专业』
最新留言
站内搜索
友情链接
我的歪酷 非非共享界
◇油库8号
◇不可回收的Nick
◇夜色中的高潮
◇Try To Remember
◇那么蓝或者到处乱走
◇中国摄影
◇马未都
◇戴老师
◇戴老师2
◇橡树
◇cnpaf
◇kendiv
◇lu0
◇Sysinternals
◇forum of sysinternals
◇Mark Russinovich's blog
◇windowsitpro
◇codeguru
◇xplus
◇codeproject
◇钱晓捷
◇MSTechNet
◇电脑编程技巧与维护
◇phrack
◇rootkit
◇planet-lab
◇刘江@图灵
◇大宝
◇VCTeamBlog
◇三言二拍
◇C++的罗浮宫
◇麦田
◇木玛
◇阿牛
◇数学网
◇歌词服务小组
ACM
IEEE
Applicable Algebra in Engineering Communication and Computing
Stochastic Processes and Their Applications
Pacific Journal of Optimization
luojw
hust
p2p research
stanford
galeer
思绮
cdCoffee
yobo
尹隐于市
于坚
刘嘉楠
Leonard Cohen
中华第一剑
曹方
参考
内地控
eee4
沙发音乐
LOOKBOOK
周C
xunxun
C专题
vckbase
jensenh
订阅 RSS
0046781
歪酷博客