1. 赋值构造函数的四种调用场景(调用时机)

场景1:

#include "iostream"

using namespace std;

 

class AA

{

public:

         AA() //无参构造函数 默认构造函数

         {      

                  cout<<"我是构造函数,自动被调用了"<<endl;

         }

         AA(int _a) //无参构造函数 默认构造函数

         {      

                  a = _a;

         }

        AA(const AA &obj2)

        {

                cout<<"我也是构造函数,我是通过另外一个对象obj2,来初始化我自己"<<endl;

                a = obj2.a + 10;

        }

         ~AA()

         {

                  cout<<"我是析构函数,自动被调用了"<<endl;

         }

         void getA()

         {

                  printf("a:%d \n", a);

         }

protected:

private:

         int a;

};

//单独搭建一个舞台

void ObjPlay01()

{

         AA a1; //变量定义

        

         //赋值构造函数的第一个应用场景

         //用对象1 初始化 对象2

         AA a2 = a1; //定义变量并初始化 //初始化法

 

         a2 = a1; //用a1来=号给a2 编译器给我们提供的浅copy

}

 

 

场景2:

第二个应用场景

//单独搭建一个舞台

void ObjPlay02()

{

         AA a1(10); //变量定义

 

         //赋值构造函数的第一个应用场景

         //用对象1 初始化 对象2

         AA a2(a1); //定义变量并初始化 //括号法

 

         //a2 = a1; //用a1来=号给a2 编译器给我们提供的浅copy

         a2.getA();

}

//注意:初始化操作等号操作 是两个不同的概念

 

场景3:

#include "iostream"

using namespace std;

 

class Location

{

public:

         Location( int xx = 0 , int yy = 0 )

         {

                  X = xx ;  Y = yy ;  cout << "Constructor Object.\n" ;

         }

         Location( const Location & p )         //拷贝构造函数

         {

                  X = p.X ;  Y = p.Y ;   cout << "Copy_constructor called." << endl ; 

         }

         ~Location()

         {

                  cout << X << "," << Y << " Object destroyed." << endl ;

         }

         int  GetX () { return X ; }                 int GetY () { return Y ; }

private :   int  X , Y ;

} ;

 

//alt + f8 排版

void f ( Location  p )  

{

         cout << "Funtion:" << p.GetX() << "," << p.GetY() << endl ;

}

 

void mainobjplay()

         Location A ( 1, 2 ) ;  //形参是一个元素,函数调用,会执行实参变量初始化形参变量

         f ( A ) ;

}

 

void main()

         mainobjplay();

         system("pause");

}

 

场景4:

第四个应用场景

#include "iostream"

using namespace std;

class Location

{

public:

         Location( int xx = 0 , int yy = 0 )

         {

                  X = xx ;  Y = yy ;  cout << "Constructor Object.\n" ;

         }

         Location( const Location & p )         //复制构造函数

         {

                  X = p.X ;  Y = p.Y ;   cout << "Copy_constructor called." << endl ; 

         }

         ~Location()

         {

                  cout << X << "," << Y << " Object destroyed." << endl ;

         }

         int  GetX () { return X ; }                 int GetY () { return Y ; }

private :   int  X , Y ;

} ;

 

//alt + f8 排版

void f ( Location  p )  

{

         cout << "Funtion:" << p.GetX() << "," << p.GetY() << endl ;

}

 

Location g()

{

         Location A(1, 2);

         return A;

}

 

//对象初始化操作 和 =等号操作 是两个不同的概念

//匿名对象的去和留,关键看,返回时如何接

void mainobjplay()

         //若返回的匿名对象,赋值给另外一个同类型的对象,那么匿名对象会被析构

         //Location B;

         //B = g();  //用匿名对象 赋值 B对象,然后匿名对象析构

 

         //若返回的匿名对象,来初始化另外一个同类型的对象,那么匿名对象会直接转成新的对象

         Location B = g();

         cout<<"传智扫地僧测试"<<endl;

}

 

void main()

         mainobjplay();

         system("pause");

}

 

09 大话设计模式C++实现之原型模式之理解深拷贝和浅拷贝

 

默认构造函数

二个特殊的构造函数

1)默认无参构造函数

当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空

2)默认拷贝构造函数

当类中没有定义拷贝构造函数时,编译器默认提供一个默认拷贝构造函数,简单的进行成员变量的值复制

构造函数调用规则研究

1)当类中没有定义任何一个构造函数时,c++编译器会提供默认无参构造函数和默认拷贝构造函数

2)当类中定义了拷贝构造函数时,c++编译器不会提供无参数构造函数

3) 当类中定义了任意的非拷贝构造函数(即:当类中提供了有参构造函数或无参构造函数),c++编译器不会提供默认无参构造函数

4 )默认拷贝构造函数成员变量简单赋值

总结:只要你写了构造函数,那么你必须用。

 

构造析构阶段性总结

1)构造函数是C++中用于初始化对象状态的特殊函数

2)构造函数在对象创建时自动被调用

3)构造函数和普通成员函数都遵循重载规则

4)拷贝构造函数是对象正确初始化的重要保证

5)必要的时候,必须手工编写拷贝构造函数

========》1个对象的初始化讲完了,增加一个案例。

深拷贝和浅拷贝

 

【浅拷贝】是增加了一个指针,指向原来已经存在的内存,在多个对象指向一块空间的时候,释放一个空间会导致其他对象所使用的空间也被释放了,再次释放便会出现错误。而【深拷贝】是增加了一个指针,并新开辟了一块空间让指针指向这块新开辟的空间。深拷贝和浅拷贝的不同之处,仅仅在于修改了下【拷贝构造函数】,以及【赋值运算符的重载】,引自https://blog.csdn.net/qq_27011361/article/details/79518057

 

  • 默认复制构造函数可以完成对象的数据成员值简单的复制
  •  对象的数据资源是由指针指示的堆时,默认复制构造函数仅作指针值复制

1浅拷贝问题抛出和分析

深拷贝浅拷贝现象出现的原因

2浅拷贝程序C++提供的解决方法

显示提供copy构造函数

显示操作重载=号操作,不使用编译器提供的浅copy

 

class Name

{

public:

         Name(const char *pname)

         {

                  size = strlen(pname);

                  pName = (char *)malloc(size + 1);

                  strcpy(pName, pname);

         }

         Name(Name &obj)

         {

                  //用obj来初始化自己

                  pName = (char *)malloc(obj.size + 1);

                  strcpy(pName, obj.pName);

                  size = obj.size;

         }

         ~Name()

         {

                  cout<<"开始析构"<<endl;

                  if (pName!=NULL)

                  {

                          free(pName);

                          pName = NULL;

                          size = 0;

                  }

         }

 

         void operator=(Name &obj3)

         {

                  if (pName != NULL)

                  {

                          free(pName);

                          pName = NULL;

                          size = 0;

                  }

                  cout<<"测试有没有调用我。。。。"<<endl;

 

                  //用obj3来=自己

                  pName = (char *)malloc(obj3.size + 1);

                  strcpy(pName, obj3.pName);

                  size = obj3.size;

         } 

 

protected:

private:

         char *pName;

         int size;

};

 

//对象的初始化 和 对象之间=号操作是两个不同的概念

void playObj()

{

         Name obj1("obj1.....");

         Name obj2 = obj1; //obj2创建并初始化

 

         Name obj3("obj3...");

 

         //重载=号操作符

         obj2 = obj3; //=号操作

 

         cout<<"业务操作。。。5000"<<endl;

 

}

void main61()

{

         playObj();

         system("pause");

}

09 大话设计模式C++实现之原型模式之理解深拷贝和浅拷贝

09 大话设计模式C++实现之原型模式之理解深拷贝和浅拷贝

多个对象构造和析构

1对象初始化列表 

1)对象初始化列表出现原因

1.必须这样做:

如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,没有默认构造函数。这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,

如果没有初始化列表,那么他将无法完成第一步,就会报错。

 

2、类成员中若有const修饰,必须在对象初始化的时候,给const int m 赋值

当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,

因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。

2)C++中提供初始化列表对成员变量进行初始化

语法规则

Constructor::Contructor() : m1(v1), m2(v1,v2), m3(v3)

{

    // some other assignment operation

}

3)注意概念

初始化:被初始化的对象正在创建

赋值:被赋值的对象已经存在

 

4)注意:

成员变量的初始化顺序与声明的顺序相关,与在初始化列表中的顺序无关

初始化列表先于构造函数的函数体执行

 

/*

1 C++中提供了初始化列表对成员变量进行初始化

2 使用初始化列表出现原因:

1.必须这样做:

如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,

而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,

如果没有初始化列表,那么他将无法完成第一步,就会报错。

 

2、类成员中若有const修饰,必须在对象初始化的时候,给const int m 赋值

当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,

因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。

*/

 

//总结 构造和析构的调用顺序

 

#include "iostream"

using namespace std;

 

class ABC

{

public:

         ABC(int a, int b, int c)

         {

                  this->a = a;

                  this->b = b;

                  this->c = c;

                  printf("a:%d,b:%d,c:%d \n", a, b, c);

                  printf("ABC construct ..\n");

         }

         ~ABC()

         {

                  printf("a:%d,b:%d,c:%d \n", a, b, c);

                  printf("~ABC() ..\n");

         }

protected:

private:

         int a;

         int b;

         int c;

};

 

 

class MyD

{

public:

         MyD():abc1(1,2,3),abc2(4,5,6),m(100)

         //MyD()

         {

                  cout<<"MyD()"<<endl;

         }

         ~MyD()

         {

                  cout<<"~MyD()"<<endl;

         }

 

protected:

private:

         ABC abc1; //c++编译器不知道如何构造abc1

         ABC abc2;

         const int m;

};

 

 

int run()

{

         MyD myD;

         return 0;

}

 

int main_dem03()

{

        

         run();

         system("pause");

         return 0;

}

构造函数与析构函数的调用顺序

1)当类中有成员变量是其它类的对象时,首先调用成员变量的构造函数,调用顺序与声明顺序相同;之后调用自身类的构造函数

2)析构函数的调用顺序与对应的构造函数调用顺序相反

相关文章:

  • 2021-09-28
  • 2021-09-25
  • 2022-02-06
  • 2021-06-08
  • 2021-07-22
  • 2021-05-18
  • 2021-11-23
  • 2021-10-09
猜你喜欢
  • 2022-12-23
  • 2021-06-01
  • 2021-11-28
  • 2021-08-29
  • 2021-11-12
  • 2022-12-23
  • 2021-10-10
相关资源
相似解决方案