精华内容
下载资源
问答
  • 今天写一个简单的文件处理工具类时遇到了一个新bug,是一个之前忽略掉的知识点,特此mark...编译器对二者处理的不同之处在于:前者通过构造函数直接对对象m_class中的成员变量进行赋值,而后者则是先初始化一个临...

    今天写一个简单的文件处理工具类时遇到了一个新bug,是一个之前忽略掉的知识点,特此mark一下。

    错误如下:

    c++类在初始化的时候有两种方式:

    1. M_CLASS m_class(...);
    2. M_CLASS m_class = M_CLASS(...);
    

    编译器对二者处理的不同之处在于:前者通过构造函数直接对对象m_class中的成员变量进行赋值,而后者则是先初始化一个临时变量并对其赋值,然后将该临时变量赋值给m_class,然后销毁这个临时变量。

    那么问题来了,如果M_CLASS包含的成员变量不能直接赋值,那么编译器就会报出如上图所示的错误。而我定义的IOFileManager这个类里面的成员变量就是两个文件流,是不可以直接赋值的!同理,包含了不可直接赋值的成员变量的类的对象也是不能够直接赋值的。

    https://blog.csdn.net/crazy_father/article/details/46660607

    所以这里初始化对象时应该采用第一种方式,或者用new来定义对象指针,还或者可以把对变量赋值的操作从构造函数中移到另外的成员函数中。

    M_CLASS* m_class = new M_CLASS(...);

    以上。

    展开全文
  • 出错原因 先介绍下博主遇到这个错误的背景情况。 有一个类A,没有定义默认构造函数A(): class A{ int m_val=0; int m_type=0; A(int val):m_val(val){ ... m_vecObjs 中的元素,并赋值给新的实例...)" (已隐式声明)

    出错原因

    先介绍下博主遇到这个错误的背景情况。

    有一个类A,没有定义默认构造函数A()

    class A{
    	int m_val=0;
    	int m_type=0;
    	
    	A(int val):m_val(val){
    	};
    	
    	A(A&&) = default; //对成员依次拷贝
    }
    

    如果直接访问std::vector< A > m_vecObjs 中的元素,并赋值给新的对象,就会报错E1776 无法引用 函数 "A::A(const A&)" (已隐式声明) -- 它是已删除的函数,因为这里默认对vector中的元素进行了拷贝操作1,而A是没有默认构造函数的,所以导致报错。

    示例代码如下:

    std::vector<A> m_vecObjs;
    m_vecObjs.push_back(A(100));
    m_vecObjs.push_back(A(200));
    m_vecObjs.push_back(A(300));
    
    //报错: E0291 类 "A" 不存在默认构造函数
    A a1;	
    
    //报错: E1776  无法引用 函数 "A::A(const A&)" (已隐式声明) -- 它是已删除的函数`
    A a2 = m_vecObjs[0];	
    
    for (int i = 0; i < m_vecObjs.size() ; i++)
    {
    	//报错: E1776  无法引用 函数 "A::A(const A&)" (已隐式声明) -- 它是已删除的函数`
    	auto a3 = m_vecObjs[i]; 
    	//TO-DO 
    }
    
    

    解决方法

    改用const auto&访问,不会进行对元素进行拷贝,避免调用“不存在的默认构造函数”。

    访问方式一:

    for (int i = 0; i < m_vecObjs.size() ; i++)
    {
    	const auto& a4 = m_vecObjs[i]; //通过
    	
    	//TO-DO 
    	std::cout << a4.m_val<< std::endl;
    }
    

    访问方式二:

    for (const auto& obj: m_vecObjs)//通过
    {
    	//TO-DO 
    	std::cout << obj.m_val<< std::endl;
    }
    

    1. https://www.cnblogs.com/Nothing-9708071624/p/10167982.html ↩︎

    展开全文
  • 关于类隐式成员函数

    2010-08-16 06:42:00
    默认构造函数,复制构造函数,赋值操作符,默认析构函数隐式地址操作符

    C++自动提供以下成员函数:
    1.默认构造函数,如果没有定义构造函数。
    2.复制构造函数,如果没有定义。
    3.赋值操作符,如果没有定义。
    4.默认析构函数,如果没有定义。
    5.地址操作符,如果没有定义。

     

    一.默认构造函数

    如果没有定义构造函数,编译器将提供ClassName::ClassName(){ }这样的空构造函数。这样的函数也可以显式的定义。需要注意的是所有参数都有默认值的构造函数也是默认构造函数。而默认构造函数只能有一个,也就是说不能出

    现:

    ClassName::ClassName(){  }

    ClassName::ClassName(int n=0){ }

    这样的定义。

     

    如果希望再创建对象时显示地对它进行初始化,或需要创建对象数组时,则必须显示的定义默认构造函数。

     

    二.复制构造函数

    复制构造函数用于将一个对象复制到新创建的对象中。也就是说,它用于初始化过程中,而不是常规的赋值过程中。

    原形通常如下:

    ClassName(const Classname &);

     

    (1)何时调用复制构造函数
    新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用。
    例如,假设motto是一个ClassName对象,则下面4种声明都将调用复制构造函数:

    //calls ClassName(const ClassName&)
    ClassName ditto(motto);
    ClassName metoo = motto;
    ClassName also = ClassName(motto);
    ClassName * pClassName = new ClassName(motto);

     

    每当程序生成了对象副本时,编译器都将使用复制构造函数。具体地说,当函数按值传递对象或函数返回对象时,都将使用复制构造函数。因为按值传递意味着创建原始变量的一个副本。编译器生成临时对象时,也将使用复制构造函数。

    例如,将3个ob对象相加时,编译器可能生成临时的ob对象来保存中间结果。

     

    (2)复制构造函数的功能
    默认的复制构造函数逐个复制非静态成员(成员复制也称为浅复制),复制的是成员的值。
    如果成员本身就是类对象,则将使用这个类的复制构造函数来复制成员对象。
    静态成员不受影响,因为它们属于整个类,而不是各个对象。

     

    (3)默认复制构造函数的潜藏BUG
    由于默认复制构造函数的浅复制规则,将引发潜藏错误。
    例如,一个类ClassName,定义了一个以字符指针为形参的构造函数,函数中用new动态分配内存,并用名为char *
    str的成员指向该内存(str = new char[100])。也就是说,这个类用来封装一个字符数组,但不使用数组,而是使用

    字符串指针。同时该类定义了析构函数,函数中使用delete[] str来释放字符串数组。
    现在定义一个ClassName的对象ob,ClassName ob("string"),
    现在有一个函数T(ClassName dob){}。接收一个ClassName实参,按值传送。
    当调用函数时T(ob),这时会创建一个实参的临时副本dob。也就是复制ob到dob,这时将调用复制构造函数,它将逐
    个复制成员变量。相当于dob.str = ob.str。注意,这里复制仅仅是复制了指针,而字符串"string"在内存中仍旧只

    有一个!这时两个对象的成员dob.str和ob.str同时指向"string"。
    当函数T()结束时,它将自动调用ClassName类的析构函数来处理临时对象dob,delete[] str,释放dob中的字符数组
    。最终造成ob.str指向的字符串也被释放。

     

    (4)使用显示复制构造函数来解决问题
    解决类设计中这种问题的方法是进行深度复制,也就是说复制构造函数应当复制字符串并将副本的地址赋值给str成
    员,而不仅仅是赋值字符串地址。那么调用析构函数时都将释放不同的字符串。

     

    注意:  如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,来复制指向的数据,而不是指针,这被称为深度复制。复制的另一种形式(成员复制或浅复制)只是复制指针值。浅复制仅复制指针信息,而不会复制指针引用的结构。

     

    三.赋值操作符
    C++允许类对象赋值,这是通过自动为类重载赋值操作符实现的。这种操作符的原型如下:
    ClassName & ClassName::operator= (const ClassName &);
    它接收并返回一个指向类对象的引用。

    (1)何时使用赋值操作符
    将已有的对象赋值给另一个对象时,将使用重载的赋值操作符:
    ClassName ob("string");
    ClassName dob;
    dob = ob;
    同时,在初始化对象时,并不一定会使用赋值操作符。
    ClassName dob = ob;
    这里dob是一个新创建的对象,被初始化为ob的值,因此使用复制构造函数。不过实现时也可能分两步来处理这条语
    句:使用复制构造函数创建一个临时对象,然后通过赋值将临时对象的值复制到新对象中。这就是说,初始化总是会调用复制构造函数,而使用=操作符也可能调用赋值操作符。

     

    (2)赋值操作符的功能
    与赋值构造函数相似,赋值操作符的隐式实现也对成员进行逐个复制。如果成员本身就是类对象,则程序将使用为这
    个类定义的赋值操作符来复制该成员,但静态数据成员不受影响。

     

    (3)赋值的潜藏BUG与解决赋值问题
    赋值操作符也会出现默认复制构造函数同样的问题:数据受损。
    解决办法是提供赋值操作符(进行深度复制)定义。其实现与复制构造函数相似,但有一些差别。
    1.由于目标对象可能引用了以前分配的数据,所以函数应使用delete[]来释放这些数据。
    2.函数应当避免将对象赋值给自身;否则,给对象重新复制之前,释放内存操作可能删除对象的内容。
    3.函数返回一个指向调用对象的引用。


    通过返回一个对象,函数可能想常规赋值操作那样,连续进行赋值,即如果S0、S1、S2都是ClassName对象,则可以

    这样编写代码:
    S0 = S1 = S2; //S0.operator= (S1.operator= (S2));

     

    下面的代码说明如何为ClassName类编写赋值操作符:
    ClassName & ClassName::operator= (const ClassName & dob)
    {
      if (this == &dob)
         return *this;                 //如果是对象赋值给自身,则直接返回该对象的引用。
      delete[] str;                    //删除当前函数调用对象所使用的动态内存空间。
      str = new char [......];
      std::strcpy(str,dob.str); //为当前函数调用对象分配新的内存空间,并复制新值。
      return *this
    }

     

    四、五

    默认析构函数不执行任何操作。
    隐式地址操作符返回调用对象的地址(即this指针的值)。

    展开全文
  • 类的隐式成员函数

    2014-06-24 18:47:24
    C++自动提供了下面这些成员函数

    C++自动提供了下面这些成员函数

    默认构造函数,如果没有定义构造函数

    复制构造函数,如果没有定义

    赋值操作符,如果没有定义

    默认析构函数,如果没有定义

    地址操作符,如果没有定义


    默认构造函数

     编译器将提供一个不接受任何参数,也不执行任何操作的构造函数,这是因为创建对象时总是会调用构造函数。默认构造函数使得类在初始化时的值时未知的。

     如果希望在创建对象时显式的对它进行初始化,或需要创建对象数组时,则必须显式的定义默认构造函数。这种构造函数没有任何参数,但是可以使用它来设定特定的值:

    Klunk::Klunk()
    {
    	klunk_ct=0;
    	...
    }
     带参数的构造函数也可以是默认构造函数,只要所有的参数值都有默认值

    Klunt(int n=0){klunt_ct=n;}
     **但只能由一个默认构造函数


    复制构造函数

    复制构造函数用于将一个对象复制到新创建的对象中。也就是说,它用于初始化过程中,而不是常规的赋值过程中。

    class_name(const class_name &)
    新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用。每当程序生成了对象的副本时,编译器都将使用复制构造函数。具体的说,当函数按值传递对象或函数返回对象时,都将使用复制构造函数。

    复制构造函数的功能:默认的复制构造函数逐个复制非静态成员,复制的是成员的值。 如果成员本身就是类对象,则将使用这个类的复制构造函数来复制成员对象。

    使用显式复制构造函数来解决问题:复制构造函数应当复制字符串并将副本的地址付给str成员,而不是复制字符串的地址。这样每个对象都有自己的字符串,而不是引用另一个对象的字符串。调用析构函数时都将释放不同的字符串,而不会试图去释放已经被释放的字符串。

    赋值操作符:c++通过重载赋值操作符实现类对象复制

    Class_name & Class_name::operator =(const Class_name &)
    与复制构造函数相似,赋值操作符的隐式实现也可以对成员逐个复制。如果成员本身就是类对象,则程序将使用为这个类定义的赋值操作符来复制该成员,但静态数据不受影响。

    解决赋值的问题:由于目标对象可能引用了以前分配的数据,所以函数应使用delete[]来释放这些数据。 函数应该避免将对象赋值给自身;否则,给对象重新赋值之前,释放内存操作可能删除对象的内容。函数返回一个指向调用对象的引用。

    应定义一个赋值构造函数,深度赋值另一个对象初始化为另一个对象,通常这种构造函数与下面类似:

    String::String(const String &st)
    {
    	num_string++;
    	len=st.len;
    	str=new char[len+1];
    	std::strcpy(str,st.str);
    }
    具体的说,赋值构造函数应该分配足够的空间信息存储赋值的数据,并赋值数据,而不仅仅是数据的地址。

    应当定义一个赋值操作,通过深度赋值将一个对象赋值给另一个对象:

    String &  String:: operator=(const String & st)
    {
    	if(this==&st)
    		return *this;
    	delete [] str;
    	len=st.len;
    	str=new char[len+1];
    	std::strcpy(str,st.str);
    	return *this;
    }
    下面包含了两个不正确的范例以及一个良好的构造函数的范例:

    String::String()
    {
    	str="default string";
    	len=std::strlen(str);
    }
    String::String(const char *s)
    {
    	len=std::strlen(s);
    	str=new char;
    	std::strcpy(str,s);
    }
    String::String(const String &st)
    {
    	len=st.len;
    	str=new char[len+1];
    	std::strcpy(str,st.str);
    }
    第一个构造函数没有使用new来初始化str。对默认对象调用析构函数时,析构函数使用delete来释放str。对不是使用new初始化的指针使用delete时,结果将是不确定的。

    第二个构造函数中使用了new,但分配的内存数量不正确,因此,new返回的内存块只能保存一个字符。

    展开全文
  • Union 是C/C++语言中的一种结构类型,用于定义可共享内存的...警告 C4624“Grade”: 将析构函数隐式定义为“已删除” 不多说,上代码: // TemplateExe1.cpp : 定义控制台应用程序的入口点。 // #include "st...
  • Union 是C/C++语言中的一种结构类型,用于定义可共享内存的...警告 C4624 “Grade”: 将析构函数隐式定义为“已删除” 不多说,上代码: 1 // TemplateExe1.cpp : 定义控制台应用程序的入口点。 2 // 3 ...
  • 很基础的操作在重载运算符的时候,尤其是和>>运算符重载,我们也许会遇到这个问题,一般情况下就是函数的声明没有写好,如这样的声明:friend std::ostream operator(std::ostream &out, <class Type> &G)这个错误...
  • 在CInterpretDlg.h中申明了 public: CEdit m_Code; ...另一个文件Lexical.h中定义一个函数Get ...无法引用函数"CEdit::CEdit(const CEdit &)"(已隐式声明)--它是已删除函数 请问是什么意思?谢谢
  • 今天在一个类中看到如下代码不是很懂,原来是c++11 新特性 RateTimer(const RateTimer&...在 C++11 中,默认函数和已删除函数使你可以显式控制是否自动生成特殊成员函数。 删除的函数还可为您提...
  • OK,等到函数结束,它将自动调用StringTest类的析构函数来处理t,于是乎delete [] str,删除t中的字符数组,结果连原来的string1的字符数组都删掉了(因为他们本来就是同一个) 乖乖。这就是浅复制了。而原本...
  • C++ 关闭函数隐式转换 在开发中遇到的一个问题,如何关闭C++函数隐式转换 C++只提供了关闭类的隐式转换,但是想要关闭某个函数隐式转换没有提供直接的方法,我们可以借助宏和模板的方法实现,实现如下图 代码...
  • 错误 C2280 Union : 尝试引用已删除函数 以及 警告 C4624 “Grade”: 将析构函数隐式定义为“已删除”的一种解决方法
  • C++ Error C2280 尝试引用已删除函数

    千次阅读 2020-11-14 11:13:30
    学习C++的右值引用的时候,发现一个错误 ...)”: 尝试引用已删除函数 1>e:\work\jutiltest\jutiltest\main.cpp(72): note: 编译器在此处生成“MyString::MyString” 1>e:\work\jutiltest\jutiltest\main
  • C++Error2208:...尝试引用已删除函数

    千次阅读 2021-02-22 09:57:51
    )”: 尝试引用已删除函数 F:\vs2015\VC\include\xutility 2581 从错误的内容看,似乎是自己的类的赋值构造函数被尝试调用却发现其删除。 在翻阅了资料后发现,erase方法会在将对象删除后,将所有该对象之后...
  • 上面如果没有写基类名调用,在创建派生类对象时,编译器会隐式调用基类的无参构造函数,这时基类要声明无参构造函数编译器才不会报错。 派生类对象中各数据成员的初始化顺序是:先调用基类构造函数,初始化基类...
  • 文章目录隐式转换隐式转换函数隐式转换丰富类功能隐式隐式隐式转换的时机隐式解析机制隐式转换的前提 隐式转换 隐式转换就是自动类型转换。 如 var dbl:Double = 12 int 自动转换double, 但是 val num:Int =3.5...
  • 按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面所示: class String { String (const char* p ); // 用C风格的字符串p作为初始化值 //… } ...
  • 如果有类成员的移动构造函数或者移动复制运算符被定义为删除或是不可访问的 有类成员是const或者引用 此外,移动操作和合成拷贝控制成员(编译器生成的拷贝成员)之间的影响:如果一个类定义了一个移动构造函数/...
  • Scala隐式转化和并发编程

    千次阅读 2016-05-05 17:40:28
    隐式函数隐式参数、隐式对象、隐式隐式函数:指有implicit前置修饰的函数 Scala会根据上下文,利用隐式转换函数的签名主要是输入类型,在程序运行时利用隐式转换函数,将接受的隐式函数参数类型定义的对象自动...
  • 观察DOM节点的子列表,为每个新元素和每个删除的元素调用一个函数。 用于为DOM节点的子代添加隐式特征,而不必担心随着时间的推移会添加/删除任何新元素。 用法 dispose = watch(element, enter, exit) 监视DOM ...
  • 隐式调用能够像使用c函数库一样使用dll中的函数,非常方便快捷。 下面是一个隐式调用的例子:dll包含两个文件dll_withlibAndH.cpp和dll_withlibAndH.h。 代码如下:dll_withlibAndH.h extern "C" __...
  • 隐式调用能够像使用c函数库一样使用dll中的函数,非常方便快捷。 下面是一个隐式调用的例子:dll包含两个文件dll_withlibAndH.cpp和dll_withlibAndH.h。 代码如下:dll_withlibAndH.h extern "C" __...
  • XPath常用函数

    万次阅读 2019-05-20 10:03:43
    有关数值的函数 有关字符串的函数 关于布尔值的函数 有关序列的函数 一般性的函数 测试序列容量的函数 Equals, Union, Intersection and Except 合计函数 生成序列的函数 上下文函数 函数示例 摘自W3...
  • scala 隐式转换详解

    2019-12-04 17:50:15
    一、scala 隐式转换引出 隐式转换的引出,先看一段代码 ...隐式转换: 以 implicit 关键字声明的, 带有单个参数的函数,这种函数 将会自动应用, 将值从一种类型转为另一种类型; 用隐式转换的概...
  • 警告:隐式声明函数‘config_setting_lookup’ [-Wimplicit-function-declaration] config_setting_t* loggers = config_setting_lookup(setting, "loggers"); 头文件我已经添加。#include <libconfig.h>

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 84,160
精华内容 33,664
关键字:

已隐式删除函数