精华内容
下载资源
问答
  • 一个空时,编译器会默认生成构造函数,拷贝构造函数,赋值函数,析构函数一个类如果重写拷贝构造函数,那么必须自定义一个构造函数。如下代码会编译出错:error C2512: “B”: 没有合适的默认构造函数可用class B ...
    1. 一个空类时,编译器会默认生成构造函数,拷贝构造函数,赋值函数,析构函数
    2. 一个类如果重写拷贝构造函数,那么必须自定义一个构造函数。如下代码会编译出错:error C2512: “B”: 没有合适的默认构造函数可用
      class B
      {
      public:
          B(const B &b)
          {
          }
      };
      
      int main(void)
      {
          B b;
      
          getchar();
          return 0;
      }
      修正为:
      class B
      {
      public:
          B() {}
          B(const B &b)
          {
          }
      };
      
      int main(void)
      {
          B b;
      
          getchar();
          return 0;
      }

    3. 拷贝构造函数和赋值函数的正确写法(if(this != &b))
      class B
      {
      public:
          B(int v)
          {
              m_value = v;
          }
      
          B(const B &b)
          {
              m_value = b.m_value;
          }
      
          B &operator =(const B &b)
          {
              if(this != &b)
              {
                  m_value = b.m_value;
              }
              return *this;
          }
      
      private:
          int m_value;
      
      };

    4. 函数返回值是对象时,要考虑return语句的效率。
      B createObj0(void)
      {
          return B(0);
      }
      B createObj1(void)
      {
          B b(0);
          return b;
      }
      createObj0创建一个临时对象并返回它,编译器直接把临时对象创建并初始化在外部存储单元中,省去了拷贝和析构的过程。createObj1则是先创建b对象,然后拷贝构造把b拷贝到外部存储单元中去,接着还会析构掉b对象。请对比下列两组代码及运行结果:
      #include <stdio.h>
      
      int g_counter = 0;
      class B
      {
      public:
          B(void)
          {
              m_value = g_counter++;
              printf("B() m_value=%d\n", m_value);
          }
      
          ~B()
          {
              printf("~B() m_value=%d\n", m_value);
          }
      
          B(const B &a)
          {
              m_value = g_counter++;
              printf("B(const B &a) m_value=%d\n", m_value);
          }
      
          B &operator=(const B&a)
          {
              printf("B &operator=(const B&a)\n");
              return *this;
          }
      
      private:
          int m_value;
      
      };
      
      B createObj0(const B b)
      {
          B bb(b);
          return bb;
      }
      
      B createObj1(const B b)
      {
          return B(b);
      }
      
      int main(void)
      {
          B __b;
          B _b = createObj0(__b);
      	return 0;
      }
      运行结果:
      #include <stdio.h>
      
      int g_counter = 0;
      class B
      {
      public:
          B(void)
          {
              m_value = g_counter++;
              printf("B() m_value=%d\n", m_value);
          }
      
          ~B()
          {
              printf("~B() m_value=%d\n", m_value);
          }
      
          B(const B &a)
          {
              m_value = g_counter++;
              printf("B(const B &a) m_value=%d\n", m_value);
          }
      
          B &operator=(const B&a)
          {
              printf("B &operator=(const B&a)\n");
              return *this;
          }
      
      private:
          int m_value;
      
      };
      
      B createObj0(const B b)
      {
          B bb(b);
          return bb;
      }
      
      B createObj1(const B b)
      {
          return B(b);
      }
      
      int main(void)
      {
          B __b;
          B _b = createObj1(__b);
      	return 0;
      }

      运行结果:
    展开全文
  • 但我们可以在一个构造方法里调用其他重载的构造方法,不是用构造方法名,而是用this(参数列表)的形式,根据其中的参数列表,选择相应的构造方法。例如: public class Person{ String name; int ...
    构造方法是在产生对象时被java系统自动调用的,我们不能在程序中像调用其他方法一样去调用构造方法(必须通过关键词new自动调用它)。但我们可以在一个构造方法里调用其他重载的构造方法,不是用构造方法名,而是用this(参数列表)的形式,根据其中的参数列表,选择相应的构造方法。例如:     
    public class Person{
            String name;
            int age;
            public Person(String name){
                this.name = name;
            }
            public Person(String name,int age){
                this(name);
                this.age = age;
            }
        }
    不是一个类有多个构造函数,而是这个把这个构造函数重载了很多次。你可以去读一下方法重载这个概念。

    构造方法重载具体好处就是:我扔进来是什么样的参数,程序就会自动找到相对应的构造方法去执行。这样构造函数就能实现很多功能了。否则一个功能写一个类,多麻烦啊。


    展开全文
  • 构造函数看似简单,实则很玄机,在构造一个类构造函数时,只要遵循以下步,便可以建立出一个正确的高效的构造函数:  1.了解C++编译器默默编写并调用了哪些函数,若不想使用编译器自动生成的函数, 就该...

    推荐一本C++经典好书:effetive c++,该篇文章部分来源于该书


    类的构造函数看似简单,实则很有玄机,在构造一个类的构造函数时,只要遵循以下几步,便可以建立出一个正确的高效的构造函数:


      1.了解C++编译器默默编写并调用了哪些函数,若不想使用编译器自动生成的函数,  就该明确拒绝(effctive c++条款5,6)


      2.定义的构造函数不能指定其返回值的类型,也不能指定为void类型。


       3.若要用类定义对象,则构造函数必须是公有型成员函数,否则类无法实例化。

         若类仅用于派生其他类,则构造函数可定义为保护型成员函数(1.为什么private不行?我理解的是只用作一次派生是可以的,

         但用作两次派生就不可以了, 因为若派生两次后,私有成员就没法再被访问了,也即基类的构造函数无法被调用了

     

      4.倘若有指针型成员变量,则要对拷贝构造函数进行重写(见我的另一篇文章:“若类中有指针型数据成员,类的几个函数的重写”)


      5..当构造函数重载或设定构造函数默认形参时,要注意避免出现二义性。

     

      6..构造函数最好使用成员初始值列表,而不要在构造函数内使用赋值操作

     

     7..考虑是不是要把构造函数设置为explict特性

     

      8.决不在构造函数和析构过程中调用virtual函数

     

     9.倘若是派生类的构造函数,则考虑是(1)用初始化成员列表值的形式调用特定的基类的构造函数还是(2)不提供初始化列表,默认调用基类的默认隐式构造函数

    展开全文
  • 构造函数 ,是一种特殊的方法 。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new...特别的一个类可以个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。

    构造函数 ,是一种特殊的方法 。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。(摘自百度百科构造函数)。



    一、最基本的构造函数

    class Base
    {
    public:
        Base(int var) : m_Var(var)
        {
        }
    private:
        int m_Var;
    };

     以上构造函数的执行过程:

    ①传参  

    ②给类数据成员开辟空间     

    ③执行冒号语法给数据成员初始化   

    ④执行构造函数括号里面的内容

    这里需要说明的是:冒号语法后面的内容相当于int a = 10;(初始化),而构造函数括号里面则是相当于是int a; a = 10;(赋初值)



    二、拷贝构造函数

    class Base
    {
    public:
        Base(int var) : m_Var(var)
        {
        }
        //拷贝构造函数
        Base(Base &ref) : m_Var(ref.m_Var)
        {
        }
    private:
        int m_Var;
    };

    为什么拷贝构造函数的参数只能用引用呢?


    这就要从拷贝构造函数式数码时候触发开始说起了,以下几种情况都会自动调用拷贝构造函数:

    用一个已有的对象初始化一个新对象的时候

    将一个对象以值传递的方式传给形参的时候

    函数返回一个对象的时候


    所以当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环直至栈溢出除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。(摘自百度百科拷贝构造函数)。

     


    拷贝构造函数,一般不需要自己编写,系统默认的拷贝构造函数就能抗住了,但是有些情况需要在构造的时候开辟空间,这时候就需要拷贝构造函数了,如下代码是摘自林锐博士的高质量C++编程指南一文。

    class String
    {
    public:
        String(const char *str = NULL); // 普通构造函数
        String(const String &other);    // 拷贝构造函数
        ~ String(void);                 // 析构函数
    private:
        char *m_data; // 用于保存字符串
    };
    // String 的析构函数
    String::~String(void) 
    {
        delete [] m_data;
        // 由于m_data 是内部数据类型,也可以写成 delete m_data;
    }
    
    // String 的普通构造函数
    String::String(const char *str) 
    {
        if(str==NULL)
        {
            m_data = new char[1]; // 若能加 NULL 判断则更好
            *m_data = '\0';
        }
        else
        {
            int length = strlen(str);
            m_data = new char[length+1]; // 若能加 NULL 判断则更好
            strcpy(m_data, str);
        }
    }
    // 拷贝构造函数
    String::String(const String &other) 
    {
        int length = strlen(other.m_data);
        m_data = new char[length+1]; // 若能加 NULL 判断则更好
        strcpy(m_data, other.m_data);
    }



     三、普通派生类构造函数的写法


    定义派生类对象的时候,会按如下步骤执行构造操作:

    ①传参     

    ②根据继承时的声明顺序构造基类    

    ③给类数据成员开辟空间    

    ④执行冒号语法后面的语句    

    ⑤执行构造函数函数体语句

    class Base
    {
    public:
        Base(int b) : m_b(b)
        {
        }
    private:
        int m_b;
    };
    
    class Derived : public Base
    {
    public:
        //普通派生类构造函数的写法
        Derived(int b, int d) : Base(b), m_d(d)
        {
        }
    private:
        int m_d;
    };


    再写一个多继承的示例:

    class Base1
    {
    public:
        Base1(int b1) : m_b1(b1)
        {
        }
    private:
        int m_b1;
    };
    
    class Base2
    {
    public:
        Base2(int b2) : m_b2(b2)
        {
        }
    private:
        int m_b2;
    };
    
    class Derived : public Base1, public Base2
    {
    public:
        Derived(int b1, int b2, int d) : Base1(b1), Base2(b2), m_d(d)
        { //注意冒号语法后面的顺序无所谓,创造基类是按照上面的继承声明顺序来进行的...
        }
    private:
        int m_d;
    };



    四、含有虚继承的派生类构造函数的写法


    为何要用到虚继承?


    虚继承主要是针对多继承时,出现二义性问题而提出的。比如,如下代码就需要用到虚继承,否则的话Derived类继承时,Base类就会不明确。


    虚继承构造函数的执行按照如下步骤:

    ①传参 

    ②创建基类,注意这时候需要显示创建所有“有参构造函数”的基类,包括直接基类,间接基类。 

    ③给类数据成员开辟空间  

    ④执行冒号语法  

    ⑤执行构造函数函数体


    注:你可能会疑惑,如下代码不是将Base间接基类创建了3次吗?其实不是这样的,编译器是这样处理的,当最远的派生类Derived创建了基类Base之后,其直接基类创建Base类的语句将会被忽略掉。

    class Base
    {
    public:
        Base(int b) : m_b(b)
        {
        }
    private:
        int m_b;
    };
    
    class Base1 : virtual public Base
    {
    public:
        Base1(int b, int b1) : Base(b), m_b1(b1)
        {
        }
    private:
        int m_b1;
    };
    
    class Base2 : virtual public Base
    {
    public:
        Base2(int b, int b2) : Base(b), m_b2(b2)
        {
        }
    private:
        int m_b2;
    };
    //虚继承,避免二义性
    class Derived : public Base1, public Base2
    {
    public:
        Derived(int b, int b1, int b2, int d) : Base(b), Base1(b, b1), Base2(b, b2), m_d(d)
        { //注意冒号语法后面的顺序无所谓,创造基类是按照上面的继承声明顺序来进行的...
        }
    private:
        int m_d;
    };


    五、关于虚析构


    虚析构一般伴随着多态而产生,多态主要方式就是用基类的指针或引用指向或引用派生类,而形成多态。


    但是这样就会存在一个问题,当我们析构的时候,由于是基类的指针,就会调用的是基类的构造函数,从而造成派生内存溢出。为了解决这个问题,引入了虚析构的概念。将基类的构造函数声明为虚,从而使其在调用析构函数的时候能够准确的调用派生类的析构函数。


    如下代码必须用到虚析构才能准确的析构派生类,并释放其占有内存。

    class Base
    {
    public:
        Base(int b) : m_b(b)
        {
        }
        //虚析构,使基类指针能准确的释放所指向的派生类里面的内容
        virtual ~Base()
        {
        }
    private:
        int m_b;
    };
    
    class Derived : public Base
    {
    public:
        Derived(int b, char *pStr) : Base(b)
        { 
            m_pStr = new char[strlen(pStr)+1];
            strcpy(m_pStr,pStr);
        }
        ~Derived()
        {
            delete m_pStr;
            m_pStr = NULL;
        }
    private:
        char *m_pStr;
    };
    
    int main(void)
    {
        char *pStr = "abcdefg";
        Base *b = new Derived(1,pStr);
        delete b;
    
        return 0;
    }

    展开全文
  • 一个类的对象作为另一个类的数据成员。 &nbsp; &nbsp; &nbsp; &nbsp;一个类中的数据成员除了可以是int, char, float等这些基本的数据类型外,还可以是某一个类一个对象。用子对象创建新。 &...
  • main中第二步执行时首先调用复制构造函数对应传入的对象b生成一个临时对象(temp),return时再次调用复制构造函数生成一个临时对象用于返回,然后temp析构,按书上说的此刻程序就走完了,但是在main中这一步Example...
  • 构造函数

    千次阅读 2016-03-07 22:28:52
    构造函数的函数名与类名相同,没有返回类型,不能声明为const成员函数(因为直到构造函数初始化过程后,对象才能真正的取得其常量属性)一个类中可以个构造函数。构造函数有一个初始化列表。   &构造函数初始...
  • c++构造函数分类说明

    千次阅读 2017-07-15 15:43:23
    在面向对象编程中,创建对象时系统会自动调用构造函数来初始化对象,构造函数种特殊的成员函数,它如下特点: 1. 构造函数的名子必须和类名相同,不能任意命名; 2. 构造函数没有返回值; 3. 构造函数...
  • C++中构造函数与复制构造函数

    千次阅读 2017-04-27 10:52:42
    在网络上朋友提到“主要原因在于编译器的优化,当复制构造函数是public时,编译器就会根据这特性来对代码进行优化。当程序运行时,编译器发现复制构造函数是public,则说明程序允许对象之间的复制,此时就会通过...
  • C++派生构造函数构造函数的执行顺序)

    万次阅读 多人点赞 2018-06-16 16:01:55
     构造函数不能被继承,构造函数不能被继承是道理的,因为即使继承了,它的名字和派生的名字也不一样,不能成为派生构造函数,当然更不能成为普通的成员函数。  在设计派生时,对继承过来的成员变量...
  • 初始化列表是用于构造函数参数的初始化,与其他函数不同,构造函数除了名字,参数列表和函数体之外,还可以初始化列表,初始化列表以冒号开头,后跟系列以逗号分隔的初始化字段。 如: class myClock { ...
  • C++中的——构造函数

    千次阅读 2018-08-29 13:57:31
    每个都分别定义了它的对象被初始化的方式,通过一个几个特殊的成员函数来控制其对象的初始化过程,这些函数叫构造函数构造函数的任务是初始化对象的数据成员,无论何时只要的对象被创建,就会执行构造...
  • C++中有一个很重要的法则:使用构造函数创建对象的顺序与使用析构函数释放对象的顺序相反。对于一些C++的初学者来说,这是一条有点费解的法则,那么该怎么理解和清晰的表现出来呢?下面我们通过程序来体现一下: #...
  • C++默认构造函数

    万次阅读 多人点赞 2018-02-08 12:43:51
    本文围绕3问题来理解C++的默认构造函数: 什么是默认构造函数? 默认构造函数什么时候被调用? 编译器在什么情况下会生成默认构造函数. 什么是默认构造函数? 我们一般会认为默认构造函数就是编译器...
  • 2编写一个有参的构造函数 3在主函数中调用无参构造函数生成圆的实例c1,调用有参构造函数生成圆的实例c2,调用实例方法判断c1和c2是否重叠   import java.util.*; class Circle { int radius;//半径 int x; ...
  • c++ 派生构造函数 与 基类构造函数的关系

    千次阅读 多人点赞 2019-05-22 10:35:00
    《面向对象程序设计基础(第二版》李师贤等,第254页:C++语言的基本规则是:创建一个派生的对象时,如果基类带有构造函数,则先调用基类的构造函数,然后才调用派生构造函数。 《Thinking in C++》,刘宗田...
  • 书上提到没有定义构造函数时进行显式初始化成员,我很纳闷,不是说没有定义构造函数的时候会合成默认构造函数吗,自己查了下,果然查到了一下转载的内容:不是未定义构造函数就一定会合成默认构造函数的!...
  • 的那些函数~~~
  • C++中构造函数调用顺序

    千次阅读 2015-09-23 17:02:28
    当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生的构造函数,依次推,直至到达派生次数最多的派生次数最多的的构造函数为止。简而言之,对象是由“底层向上”开始构造的。因为,构造函数一...
  • 快要有一个月没有更新博客了,是时候再动一动笔啦!因为最近在学习C++,在学习过程中看了好多书,也在实际训练中遇到了一些问题。所以在接下来的时间里,应该会对C++里自己...所以,我们必要对构造函数一个全面的
  • 自定义View的四个构造函数

    千次阅读 2019-03-29 13:51:16
    自定义View继承View或者ViewGroup都会让我们实现构造函数,通常会实现一个参数的构造函数,两个参数的构造函数和三个参数的构造函数,它们什么区别,又为什么要实现这么多构造函数呢? public class DemoView77 ...
  • 在学习群里面看到一位同学问——一个类中可以定义多个空参数的构造方法吗 我当是在想应该不行的吧,然后看到那个问问题的同学说:“可以再定义局部的空参构造方法”,然后自己看了一下关于局部的知识确实阔以,...
  • 默认构造函数构造函数重载

    万次阅读 多人点赞 2017-09-29 08:15:52
    对象被创建时,编译器为对象分配内存空间,并自动调用该构造函数,由构造函数完成数据成员的初始化工作。、默认构造函数 从代码层面进行分析 class testClass { public : testClass();//不带参数的默认
  • 在android动画中,最常用的一个莫不是... 关于TranslateAnimation几个构造函数的参数意义,曾困惑我不少时间,参考官方文档和网上的讲解,通过试验总结出一些自己的理解,如果误敬请指正。  Translate
  • 【C++】C++和对象、构造函数和析构函数

    千次阅读 多人点赞 2018-06-03 20:32:37
    是对某一事物的抽象描述,具体地讲,是C++中的一种构造的数据类型。它即可包含描述事物的数据,又可包含处理这些...定义一个类的一般格式为: class 类名{ private: 成员表1; public: 成员表2; protected:...
  • 在对Java代码进行优化的时候,想方设法的要提高整体的效率,使用JProfiler看代码的时间占比,然后,看看...1,能使用构造函数一步到位的,就尽量使用构造函数,而不是使用一个个setter函数 2,能使用数组的,就使...
  • 一个class只能有一个用于构造对象的__init__函数但python中的变量是无类型的,因此传给__init__的参数可以是任何类型python中的函数参数在定义时可以默认值,可以让__init__函数接受多个参数,在后面的一些参数给...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 649,503
精华内容 259,801
关键字:

一个类有几个构造函数