默认构造函数和拷贝构造函数

默认构造函数:

class testClass
{
public:
    testClass();                    /* 默认构造函数 */
    testClass(int a, char b);        /* 构造函数 */
    testClass(int a=10,char b='c');    /* 默认构造函数 */

private:
    int  m_a;
    char m_b;
};
  1. 默认构造函数主要是用来完成如下形式的初始化的:
 testClass classA;
 // 或者  testClass *classA = new testClass;

在这种情况下,如果没有提供默认构造函数,编译器会报错;

非默认构造函数在调用时接受参数,如以下形式:

 1testClass classA(12,'H');
 2//或者  testClass *classA = new testClass(12,'H');
  1. 如果程序猿没有定义任何构造函数,则编译器会自动定义默认构造函数,其形式如 testClass() {}; 可以看出,编译器自动提供的默认构造函数是 啥也没有啊 ;

  2. 定义默认构造函数有两种方式,如上述代码展示的,一是定义一个无参的构造函数,二是定义所有参数都有默认值的构造函数 ;

  3. 注意:一个类只能有一个默认构造函数!也就是说上述两种方式不能同时出现,一般选择 testClass(); 这种形式的默认构造函数 ;

  4. 只要程序猿定义了构造函数,编译器就不会再提供默认构造函数了,所以,程序猿最好再手动定义一个默认构造函数,以防出现 testClass a; 这样的错误。
    什么时候调用默认构造函数?

1.如果一个类没有默认构造函数,但是这个类中含有一个另外一个类的对象,并且这个类含有默认构造函数,则编译器会为该类合成一个默认构造函数,例如:

class Foo
{
public:
    ...
    Foo();
    Foo(int);
    ... 
}

class Bar
{
public:
    char *str;
    Foo foo;//Foo类含有默认构造函数,所以编译器会为Bar生成一个默认构造函数,但是这个构造函数并不会去出初始化str,这个str指针需要程序员去初始化
    //编译器合成的默认构造函数可能会是这样:
    Bar::Bar()
    {
        foo.Foo::Foo();  //伪代码,这只是为了满足编译器的需要
    }
}

如果程序员在Bar中定义了构造函数,则编译器不会再去为Bar生成默认构造函数,而是在Bar的构造函数中插入一些代码,比如:

Bar::Bar()
{
    foo.Foo::Foo();//编译器自己插进去的必须放在str初始化之前
    str=nullptr;
}

2.一个带有默认构造函数的基类派生出一个没有默认构造函数的子类,编译器会为子类生成一个默认构造函数,在这个构造函数中调用基类的默认构造函数。
3.继承自一个带有虚函数的父类,因为需要在子类中处理相关的虚函数表,所以需要为子类生成一个默认构造函数,初始化虚函数表
4.子类虚继承基类,此处比较复杂,详见《深度探索c++对象模型》46页

拷贝构造函数的调用时机:
1当用类的一个对象初始化该类的另一个对象时.例如:

int main()
{
   point A(1,2);
   point B(A);//用对象A初始化对象B,拷贝构造函数被调用.
}

2 如果函数的形参是类的对象,调用函数时,进行形参和实参结合时.

void f(point p)
{
}
main()
{
   point A(1,2);
   f(A);//函数的形参为类的对象时,当调用函数时,拷贝构造函数被调用.
   //编译器做的工作:
   //point p(A); 这里调用point的拷贝构造函数,生成一个临时的p对象,实行的是浅拷贝
   //f(p); f函数结束后,p对象中new的内存将会被释放掉,此后再调用相关对象A的操作将会出错,因为浅拷贝的内存已经被释放了,所以f函数最好是传递一个引用进去
}

3 如果函数的返回值是类的对象,函数执行完成返回调用者时.

point g()
{
   point A(1,2);
   return A;//函数的返回值是类的对象,返回函数值时,调用拷贝构造函数.
   //编译器的工作:
   //void g(point &p) //讲返回值设置空,并给参数加一个point的引用
   //{
   //   point A(1,2);
   //   ...
   //   p.point::point(A);//返回前调用拷贝构造函数用A初始化p; 
   //   return;
   //}
}
void main()
{  
   point B;
   B = g();
}

4、需要产生一个临时类对象时。

你可能感兴趣的:(c++)