java 赋值运算符、拷贝初始化和this指针

   1)首先区别什么是赋值,什么是初始化。

  2)程序中重载采用了引用传递,原因:①众所周知,用值传递的参数将在要传递的函数内产生一个副本,没有例外。如果这个对象很大,则副本就会浪费汗多空间。②在某些情况下可能想记录对象的数目。如果编译器在使用赋值运算符时,每次产生一个额外的对象,这样就可能见到比医疗多得多的对象。而引用传递有助于避免创建过多的对象。

  3)return alpha(data); 返回值是重载函数所在的对象的一个副本,而不是同一个对象。返回的值可使它将运算符=串联起来:a3=a2=a1;

  4) 然而alpha operator = (alpha& a)中值的返回与值的参数一样的缺点:浪费内存空间。但是使用引用来返回函数的值如alpha& operator = (alpha& a) 这样行吗?

  回答是不行的:在函数内部创建的非static的局部变量,在函数返回时即被销毁,引用所返回的值,仅仅是实际希望返回值得地址,是没有意义的,甚至会出现严重错误。(在这里我们可以用this指针解决这个问题,后文会解释)

  注意:赋值运算符是唯一一个不能继承的运算符。如果在基类重载了赋值运算符,那么在任何派生类中都不能再重载同一函数。

 代码如下  

#include<iostream>
using namespace std;
class  alpha
{
public:
 alpha():data(0) {}       //没有参数的构造函数
 alpha(int d):data(d) {}  //一个参数的构造函数
 void diplay()            //显示数据
 {
  cout<<data<<endl;
 }
 alpha(alpha& a)          //重载拷贝构造函数
 {
  data=a.data;
  cout<<"copy constructor invoked! "<<endl;
 }
 alpha operator = (alpha& a) //重载赋值运算符
 {
  data=a.data;
  cout<<"assignment operator invoked! "<<endl;
  return alpha(data);  //单参数的构造函数
 }
private:
 int data;
};
int main()
{
 alpha a1(32);

 alpha a2;     //无参数构造函数
 a2=a1;        //赋值运算符
 a2.diplay();

 alpha a3=a1;  //拷贝构造函数
 a3.diplay();

 alpha a4(a1);  //拷贝构造函数
 a4.diplay();

 return 0;
}

  .看函数的几种情况

  1)函数参数

  view sourceprint?void func(alpha); //以值传递对象

  func(a1); //函数调用

  这时拷贝构造函数将会被调用来创建一个对象a1的副本,并将副本交给函数func()操作。(当然引用或者指针就不会调用拷贝构造函数)

  2)函数返回值

  view sourceprint?alpha func() //函数声明

  a2=func() //函数调用

  在这里:首先,程序调用拷贝构造函数来穿件一个func()返回值的副本;

  然后,这个值再被赋给a2(调用赋值运算符)。

  3)拷贝构造函数为alpha(alpha& a) ,为什么不是alpha(alpha a)的形式?

  答:拷贝构造函数必须使用引用,否则会报告内存溢出。(因为如果参数用值来传递,就需要创建一个该值的副本。如何创建副本呢?使用拷贝构造函数,但是原函数本来就是要定义拷贝构造函数,这样不断调用自己你说会有什么结果!~)

  二、this指针

  每一个对象的成员函数都可以访问一种神奇的指针,即指向该对象本身的this指针,因而在任何对象中都可找到所属对象的自身地址。

 代码如下  

#include<iostream>
using namespace std;
class  alpha
{
public:
 alpha():data(0) {}       
 alpha(int d):data(d) {}  
 void display()            
 {
  cout<<data<<endl
   <<this->data<<endl;
 }
 //alpha operator = (alpha& a) //重载赋值运算符
 //{
 // data=a.data;
 // cout<<"assignment operator invoked! "<<endl;
 // return alpha(data);  //单参数的构造函数
 //}
 alpha& operator = (alpha& a) //重载赋值运算符
 {
  data=a.data;
  cout<<"assignment operator invoked! "<<endl;
  return *this;     //通过this指针返回值
 }
private:
 int data;
};
int main()
{
 alpha a1(37);
 a1.display();  //直接输出和this->data的输出结果是一样的
 alpha a2,a3;
 a3=a2=a1;    //调用赋值运算符
 cout<<"a2=";a2.display();
 cout<<"a3=";a3.display();
 return 0;
}

  注意实例中的:使用this指针返回值。(从成员函数和重载运算符返回值,this指针是一个更实用的用法)

  1)this指针指向的是该成员函数所属的对象,所以*this就是这个对象本身。通常实用引用和this指针从重载赋值运算符返回数据,从而避免创建额外的对象。

  2)必须注意:this指针在静态成员函数中是无效的,因为静态成员函数不属于任何特定的对象。

  三、dynamic_cast和typeid

  这两个功能通常使用在有很多类都由一个基类派生的情况下。为了使动态类型转换能够工作,基类必须是多态的(也就是说至少包含一个虚函数)。

  1.dynamic_cast可以改变指针类型

 代码如下  

#include<iostream>
#include<typeinfo>
using namespace std;
class Base
{
public:
 Base() {}
 virtual void vertfunc()  //要想用dynamic_cast,基类必须是多态类型
 {}
 Base(int b):ba(b){}
 void show()
 {
  cout<<"Base: ba="<<ba<<endl;
 }
protected:
 int ba;
};
class derv1:public Base
{};
class derv2:public Base
{
public:
 derv2():Base() {}
 derv2(int b,int d):Base(b),da(d) {}
 void show()
 {
  cout<<"derv2: ba="<<ba<<" da="<<da<<endl;
 }
private:
 int da;
};
bool isDerv1(Base* pUnknown)
{
 derv1* pderv1;
 if (pderv1=dynamic_cast<derv1*>(pUnknown))
  return true;
 else
  return false;
}
int main()
{
 derv1* d1=new derv1;
 derv2* d2=new derv2;
 if (isDerv1(d1))
  cout<<"d1是类derv1的一个对象"<<endl;
 else
  cout<<"d1不是类derv1的一个对象"<<endl;
 if (isDerv1(d2))
  cout<<"d2是类derv1的一个对象"<<endl;
 else
  cout<<"d2不是类derv1的一个对象"<<endl;

 Base* pbase=new Base(10);
 derv2* pderv=new derv2(22,33);
 pbase->show();pbase=dynamic_cast<Base*>(pderv); pbase->show(); //派生类到基类
 pbase=new derv2(34,32);
 pderv->show(); pderv=dynamic_cast<derv2*>(pbase); pderv->show();  //基类到派生类
 return 0;
}

时间: 2024-08-20 11:56:18

java 赋值运算符、拷贝初始化和this指针的相关文章

实例分析c++拷贝初始化与直接初始化的底层区别

阅读说明:对于前面代码看不懂的朋友,可以先跳到最后看总结,然后再回头看上文内容,或者会有豁然开朗的感觉. 开发运行环境:visual studio 2013 源代码 #include <iostream>  #include <cstring>  using namespace std;class ClassTest{public:    ClassTest()    {        c[0] = '\0';        cout << "ClassTes

java的数组初始化

在C中初始化数组极易出错,而且相当麻烦.C++通过"集合初始化"使其更安全(注释⑥).Java则没有象C++那样的"集合"概念,因为Java中的所有东西都是对象.但它确实有自己的数组,通过数组初始化来提供支持. 数组代表一系列对象或者基本数据类型,所有相同的类型都封装到一起--采用一个统一的标识符名称.数组的定义和使用是通过方括号索引运算符进行的([]).为定义一个数组,只需在类型名后简单地跟随一对空方括号即可: int[] al; 也可以将方括号置于标识符后面,获

java中static初始化模块的使用

问题描述 java中static初始化模块的使用 我在编写中反复调用一个类中的方法,该类中有一个静态初始化模块static{},没有主方法,那么这个类的初始化模块会不会反复初始化? 怎么让它之初始化一次? 是在作c/s模型中出现的,客户端发送请求,要求修改服务器端的static模块,修改成功后,再次访问static模块又初始化了. 解决方案 java中static的使用java-static的使用java static final 初始化 解决方案二: 它本来就只初始化一次 解决方案三: 静态类

求助,在线等,java+ssm项目初始化数据问题解析json文件加载到数据库,跪谢!

问题描述 求助,在线等,java+ssm项目初始化数据问题解析json文件加载到数据库,跪谢! 服务器能不能在启动的时候加载json文件 然后把数据 加载到数据库!就是启动服务器,然后启动成功后,数据库要看到有基本数据的效果,可以实现吗?在线等!跪谢!

c++-“使用拷贝初始化时,只能提供一个初始值”是什么意思?

问题描述 "使用拷贝初始化时,只能提供一个初始值"是什么意思? <C++ Primer>第五版,中文版.88 页. 提供两个初始值是什么样的? when we use the copy initialization form (i.e., when we use =) (§ 3.2.1, p. 84), we can supply only a single initializer; 解决方案 你不可能用两个值来初始化对象吧 解决方案二: 这句话的意思是当你是用拷贝初始化的

java 初始化-Java类的初始化顺序问题

问题描述 Java类的初始化顺序问题 一般在Java对象能够调用方法之前,此类中的成员变量就已经初始化完毕,那如果这个成员是匿名内部类呢?也会等到这个匿名内部类中的代码全部跑完吗? 解决方案 Java初始化顺序1在new B一个实例时首先要进行类的装载.(类只有在使用New调用创建的时候才会被java类装载器装入)2,在装载类时,先装载父类A,再装载子类B3,装载父类A后,完成静态动作(包括静态代码和变量,它们的级别是相同的,安装代码中出现的顺序初始化)4,装载子类B后,完成静态动作类装载完成,

java 关于数组初始化的问题

问题描述 java 关于数组初始化的问题 为什么这里输出的是0 而不是 7 解决方案 一楼说的对,一般顺序为(这三者):变量,构造器,方法,当int n:系统默认n=0,所以初始化时b的长度等于0.我知道你想问的是:t.b.length,不是应该是通过t这个对象吗,但是数组一旦初始化长度就不能改了,所以导致打印输出时为0,懂了吧. 解决方案二: 因为一个对象初始化,他的成员变量要先于函数执行,构造函数也不例外,b是成员变量,初始化b的时候n还等于0 解决方案三: 你在成员变量和构造方法前都打个断

java中有时候初始化一个对象不需要new关键词

问题描述 java中有时候初始化一个对象不需要new关键词 java中有时候初始化一个对象不需要new关键词 比如 camera =Camera.open( ); 就不需要new关键词 还有那些类初始化可以像这样子的呢 解决方案 camera =Camera.open( ); 那必然有 class Camera { static public Camera open() { return new Camera(); } } 这样的代码. 封装在里面,你看不到而已. 解决方案二: 静态方法可以这样

java变量的初始化和属性的默认值

问题描述 java变量的初始化和属性的默认值 java变量的初始化和属性的默认值问题. 为什么local variables 使用时要赋初值,而global variables 系统默认初值?(我这样理解对吗?本人小白,求各路大神指点!) 解决方案 对于类成员,会自动附初值,对于方法内部变量,不会,你最好给一下值 解决方案二: 这个你用时手动给一下值就是了,也没有那么麻烦吧. 解决方案三: 对于成员变量,都有对应的默认值,而对于局部变量,在使用前必须先赋值,你可以自己写代码验证下. 解决方案四: