[C++_G_CLASS] C++中类的构造函数

首先看一个题目:
有一个类
class A
{
public:
    A();                                    //c1
    A(const A&);                      //c2
    A(int i);                               //c3
    A& operator=(const A&);   //c4
};
问如下语句都调用哪些构造函数?

A a;           //s1
A b=a;      //s2
b=a;         //s3
A c();        //s4
A b(a);      //s5
A()=5;      //s6

先讲一下收获:

   1 一个类一般要提供3个构造函数,默认构造函数; 拷贝构造函数; 赋值函数(operator=重载)。
      如果不定义这3个函数,编译器也会生成缺省的默认构造函数; 拷贝构造函数。( 赋值函数不太确定是否会生成缺省的)。

   2 拷贝构造函数和赋值函数,缺省情况下,实行位拷贝。
      类中可能含有指向某内存空间的指针,是定义这两个函数的主要原因。你需要决定是否要求指针指向同一空间,或者再次分配内存。

   3 使用默认构造函数时,必须不能使用括号。
   例如s1, s4。s1显然是调用c1。s4呢?s4是声明了一个返回值为A的函数。

   4 拷贝构造函数和赋值函数的区别,拷贝构造函数在建立对象的时候使用; 而赋值函数在赋值时引用(废话:))
    例如s2是调用c2。s3是调用c4。如果他们中任何一个没定义,那么相应的调用就会使用位拷贝.
    可能s2中的语法令人和s3混淆,s5中的语法就相当清晰了。

   5 如果类中定义了包含某类型T的参数的构造函数,则就有了T到类的类型转换。
   例如s6。5是int型的,类A有这样的参数的构造函数,那么先将5利用相应的构造函数( A(int) )转化为A的对象,或者说是生成一个A的对象。等号左边,显然是调用默认构造函数生成一个类的对象。最后调用赋值函数,完成赋值!

   6 还得谈一下编译器的区别。
    A b()
   {
      A a;
      return a;
    }

    A c=b();

   在G++下,上面的代码是不调用拷贝构造函数或默认构造函数的。
   而使用VC下,是调用拷贝构造函数的。
   我个人也是认为应该调用拷贝构造函数,首先是由局部变量生成返回的临时变量,其次是由返回值构造新的对象。需要调用两次。但这里编译器G++做了优化。
    如果在拷贝函数中改变了某个成员变量i的值,那么上面的代码是不会成功的。
    比如i默认构造为0, 拷贝构造函数把它修改为2, 然后经过上面的代码,在g++下c.i仍然是0而不是2。



实验代码如下:
平台
g++ version 4.0.3
Ubuntu 6.06 LTS - the Dapper Drake - released in June 2006

#include <cstdio>
//using namespace std;

/*
    拷贝构造函数和=号重载的作用在于
    防止位拷贝对类中指针,既而内存使用的影响
    析构函数要合理的释放内存

    =号重载在VC中是要求必须有返回值的。
    =号重载记得要判断是否是自赋值。
    =号重载最好是返回A&。这样就提高了效率。
  */
class A
{
    //除const static的变量可以在类体内赋值外,其余变量均不可以赋值
    int i;

public:

    //默认构造函数
    A()
    {
        i=0;
        printf("A/n");
    }

    //拷贝构造函数
    //拷贝构造函数的作用主要在于:如果类中含有指针,可以决定
    //                该指针是否需要指向新的内存空间
    //                否则,位拷贝的话只是完成简单的复制。
    A(const A&)
    {
        i=1;
        printf("AConst/n");
    }
   
    //一般构造函数
    A(int i)
    {
        i=2;
        printf("AInt/n");
    }

    //=号重载
    //返回值如果是A,则如果有return语句,则会调用拷贝构造函数
    //         A& 则不会
     A& operator=(const A&)
    {
        i=3;
        printf("A=/n");
        //
        return *this;
        /*
        A a;
        //此时也不调用拷贝构造函数, 编译器优化了?
        //答案应该是肯定的。VC编译器中没有对此作优化,仍然需要调用
        return a;
        */
    }

    void speak()
    {
        printf("i = %d/n",i);
    }

    static void CSpeak()
    {
        printf("I'm the class!/n");
    }
};

int main (int argc, char * argv[])
{
    printf("Test 1: /n");
    A a;
    a.speak();
    printf("/n");
   
    printf("Test 2: /n");
    //先调用A(int),利用参数5构造一个A对象
         //                            或说成将5强制类型转换为A
    //然后调用默认构造函数构造一个A对象
    //再然后利用重载运算符赋值
    A()=5;
    printf("/n");

    printf("Test 3: /n");
    //不是声明对象,而是声明函数
    A b();
   
    b().speak();;
    printf("/n");

    printf("Test 4: /n");
    A * c=new A();
    printf("/n");

    printf("Test 5: /n");
    A d;
    A e;
    d=e;//如果不重载运算符,不会调用拷贝构造函数
    d.speak();
    e.speak();
    printf("/n");
   
    printf("Test 6: /n");
    A f;
    A g=f;//此时调用拷贝构造函数
    printf("/n");


    return 1;
}


A b()
{
    /*
    A a;
    a.speak();
    //不调用拷贝构造函数,VC编译器中没有对此作优化,仍然需要调用
    return a;
    */

    //调用拷贝构造函数
    return (*(new A()));
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值