精华内容
下载资源
问答
  • C++构造函数中用参数列表初始化成员

    万次阅读 多人点赞 2015-09-29 14:57:54
    C++构造函数中初始化成员参数列表初始化成员(必须用的原因:对象成员的初始化,const修饰的成员的初始化,引用成员的初始化,子类调用父类的构造函数初始化父类成员)参数列表在构造函数执行之前执行,参数列表中执行...

    C++构造函数中初始化成员参数列表初始化成员(必须用的原因:对象成员的初始化,const修饰的成员的初始化,引用成员的初始化,子类调用父类的构造函数初始化父类成员)参数列表在构造函数执行之前执行,参数列表中执行的是初始化(所有的成员,无论是否出现在参数列表中,都会有初始化),参数列表的执行顺序与类中成员的声明顺序,与类的继承顺序相一致构造函数中执行的一般是赋值多重继承,虚继承构造函数的参数初始化列表的区别
    类对象的构造顺序是这样的:
    1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员;
    2.进入构造函数后在构造函数中执行一般赋值与计算。
    使用初始化列表有两个原因:
    原因1.必须这样做:
    《C++ Primer》中提到在以下三种情况下需要使用初始化成员列表:

    一、需要初始化的数据成员是对象的情况(这里包含了继承情况下,通过显示调用父类的构造函数对父类数据成员进行初始化);
    二、需要初始化const修饰的类成员;
    三、需要初始化引用成员数据;
    即:

    例一、数据成员是对象,切对象只有含参数的构造函数;
    如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。

    class Test
    {
    public:
             Test(int x,int y,int z);
    private:
             int a;
             int b;
             int c;
    };
    class MyTest
    {
    public:
            MyTest():test(1,2,3){}        //初始化,初始化列表在构造函数执行前执行(这个可以测试,对同一个变量在初始化列表和构造函数中分别初始化,首先执行参数列表,后在函数体内赋值,后者会覆盖前者)。
    private:
            Test test;            //声明
    };

    因为Test有了显示的带参数的构造函数,那么他是无法依靠编译器生成无参构造函数的,所以没有三个int型数据,就无法创建Test的对象。
    Test类对象是MyTest的成员,想要初始化这个对象test,那就只能用成员初始化列表,没有其他办法将参数传递给Test类构造函数。

    例二、对象引用或者cosnt修饰的数据成员
    另一种情况是这样的:当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
    即:

    class Test
    {
         priate:
              const int a;   //const成员声明
         public:
              Test():a(10){}  //初始化
    };
    或
    class Test
    {
        private:
             int &a;   //声明
        public:
             Test(int a):a(a){}  //初始化
    }

    例三、子类初始化父类的私有成员,需要在(并且也只能在)参数初始化列表中显示调用父类的构造函数,如下:

    class Test
    {
     private:
          int a;
          int b;
          int c;
     public:
          Test(int a,int b,int c)
          {
               this->a = a;
               this->b = b;
               this->c = c;
          }
          int getA(){return a;}
          int getB(){return b;}
          int getC(){return c;}
    };
    class MyTest:public Test
    {
     private:
          int d;
     public:
          MyTest(int a,int b,int c,int d):Test(a,b,c)
          //MyTest(int a,int b,int c,int d)
          { 
              //Test(a,b,c);   //构造函数只能在初始化列表中被显示调用,不能在构造函数内部被显示调用
           this->d = d;
          }
          int getD(){return d;}
    }; 
    
    int main(int argc,char *argv[])
    {
         MyTest mytest(1,2,3,4);
         printf("a=%d,b=%d,c=%d,d=%d\n",
         mytest.getA(),mytest.getB(),mytest.getC(),mytest.getD());
         return 0;
    }

    多重继承,虚继承构造函数的参数初始化列表的区别:
    代码如下:
    注意多重继承子类的构造函数

    #include <stdio.h>
    
    class CTop
    {
    private:
        int a;
    public:
        int getA()
        {
            return a;
        }
        CTop(int a)
        {
            this->a  = a;
        }
    };
    
    class CLeft:public CTop
    {
    private:
        int b;
    public:
        int getL()
        {
            return b;
        }
        CLeft(int a,int b):CTop(a)
        {
            this->b = b;
        }
    };
    
    class CRight:public CTop
    {
    private:
        int c;
    public:
        int getR()
        {
            return c;
        }
        CRight(int a,int c):CTop(a)
        {
            this->c = c;
        }
    };
    
    class Test:public CLeft,public CRight
    {
    private:
        int d;
    public:
        int getT()
        {
            return d;
        }
        Test(int a,int b,int c,int d):CLeft(a,b),CRight(a,c)
        {
            this->d = d;
        }
    };
    
    int main(int argc,char *argv[])
    {
        Test obj(1,2,3,4);
         printf("obj.a=%d,obj.b=%d,obj.c=%d,obj.d=%d\n",
         obj.CLeft::getA(),obj.getL(),obj.getR(),obj.getT());   //getA有歧义,要用类名来做区分。
        return 0;
    }

    注意虚继承子类的构造函数

    #include <stdio.h>
    
    class CTop
    {
    private:
        int a;
    public:
        int getA()
        {
            return a;
        }
        CTop(int a)
        {
            this->a  = a;
        }
    };
    
    class CLeft:virtual public CTop
    {
    private:
        int b;
    public:
        int getL()
        {
            return b;
        }
        CLeft(int a,int b):CTop(a)
        {
            this->b = b;
        }
    };
    
    class CRight:virtual public CTop
    {
    private:
        int c;
    public:
        int getR()
        {
            return c;
        }
        CRight(int a,int c):CTop(a)
        {
            this->c = c;
        }
    };
    
    class Test:public CLeft,public CRight
    {
    private:
        int d;
    public:
        int getT()
        {
            return d;
        }
        Test(int a,int b,int c,int d):CLeft(a,b),CRight(a,c),CTop(a)
        {
            this->d = d;
        }
    };
    
    int main(int argc,char *argv[])
    {
        Test obj(1,2,3,4);
        printf("obj.a=%d,obj.b=%d,obj.c=%d,obj.d=%d\n",
        obj.getA(),obj.getL(),obj.getR(),obj.getT());      //因为采用虚基类,虚继承机制保证了a只有一份,所以不存在歧义。
        return 0;
    }

    原因2.效率要求这样做:
    类对象的构造顺序显示,进入构造函数体后,进行的是计算,是对成员变量的赋值操作,显然,赋值和初始化是不同的,这样就体现出了效率差异,如果不用成员初始化类表,那么类对自己的类成员分别进行的是一次隐式的默认构造函数的调用,和一次赋值操作符的调用,如果是类对象,这样做效率就得不到保障。
    注意:构造函数需要初始化的数据成员,不论是否显示的出现在构造函数的成员初始化列表中,都会在该处完成初始化,并且初始化的顺序和其在类中声明时的顺序是一致的,与列表的先后顺序无关,所以要特别注意,保证两者顺序一致才能真正保证其效率和准确性。
    为了说明清楚,假设有这样一个类:

    class foo{
          private :
              int a, b;
    };

    1、foo(){}和foo(int i = 0){}都被认为是默认构造函数,因为后者是默认参数。两者不能同时出现。
    2、构造函数列表的初始化方式不是按照列表的的顺序,而是按照变量声明的顺序。比如foo里面,a在b之前,那么会先构造a再构造b。所以无论foo():a(b + 1), b(2){}还是foo():b(2),a(b+1){}都不会让a得到期望的值。
    3、构造函数列表能够对const成员初始化。比如foo里面有一个int const c;则foo(int x) : c(x){}可以让c值赋成x。
    不过需要注意的是,c必须在每个构造函数(如果有多个)都有值。
    4、在继承里面,只有初始化列表可以构造父类的private成员(通过显示调用父类的构造函数)。比如说:

    class child : public foo
    {
    };

    foo里面的构造函数是这样写的:

    foo (int x)
    {
           a = x;
    }.

    而在child里面写child(int x){ foo(x); }是通过不了编译的。
    只有把子类构造函数写作child (int x) : foo(x){}才可以。

    展开全文
  • C++中默认构造函数和构造函数初始化列表

    千次阅读 多人点赞 2018-12-13 10:59:45
    1、默认构造函数和构造函数 (1)构造函数:C++用于构建类的新对象时需要调用的函数,该函数无返回类型!...只要程序员定义了构造函数,编译器不会再提供默认构造函数了。 定义默认构造函数有两种方式,...

    1、默认构造函数和构造函数

    (1)构造函数:C++用于构建类的新对象时需要调用的函数,该函数无返回类型!(注意:是“无”! 不是空!(void))。

    (2)默认构造函数默认构造函数是在调用时不需要显示地传入实参的构造函数。

    一个类如果自己没有定义构造函数,则会有一个无参且函数体也是空的默认构造函数。只要程序员定义了构造函数,编译器就不会再提供默认构造函数了。

    定义默认构造函数有两种方式,一是定义一个无参的构造函数,二是定义所有参数都有默认值的构造函数

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

    (3)编译器在什么情况下会生成默认构造函数?

    下面几种情况下,编译需要生成默认构造函数:

    • 当该类的类对象数据成员有默认构造函数时。
    • 当该类的基类有默认构造函数时。
    • 当该类的基类为虚基类时。
    • 当该类有虚函数时。

    (4)避免“无参数的默认构造函数”和“带缺省参数的默认构造函数”同时存在

    无参数的默认构造函数和带缺省参数的默认构造函数同时存在时,编译器会产生二义性,从而生成编译错误

    class Sample {
    public:
        // 默认构造函数
        Sample() {
            // do something
            printf("Sample()");
        }
    
        // 默认构造函数
        Sample(int m = 10) {
            // do something
            printf("Sample(int m = 10)");
        }
    };
    
    
    int main()
    {
        Sample s; // error C2668: “Sample::Sample”: 对重载函数的调用不明确
    
        return 0;
    }
    

    2、构造函数初始列表

    C++类中成员函数一般有两种初始化,一种是在类的构造函数内部初始化,另一种是利用类的构造函数的初始化列表进行初始化。初始化和赋值对内置类型的成员没有什么大的区别。对非内置类型成员变量,为了避免两次构造,推荐使用类构造函数初始化列表。

             初始化数据成员与对数据成员赋值的含义是什么?有什么区别?

    首先把数据成员按类型分类并分情况说明:

    (1)内置数据类型,如int,float等;复合类型(指针,引用)

            在成员初始化列表和构造函数体内进行,在性能和结果上都是一样的

    (2)用户定义类型(类类型)

            结果上相同,但是性能上存在很大的差别。因为类类型的数据成员对象在进入函数体前已经构造完成,也就是说在成员初始化列表处进行构造对象的工作,调用构造函数,在进入函数体之后,进行的是对已经构造好的类对象的赋值,又调用个拷贝赋值操作符才能完成(如果并未提供,则使用编译器提供的默认按成员赋值行为)。因此,能使用初始化列表的时候尽量使用初始化列表。

    class Test2
    {
    public:
        Test1 test1 ;
        Test2(Test1 &t1):test1(t1){}    //调用拷贝构造函数初始化test1,省去了调用默认构造函数的过程
    }
    

    3、必须用带有初始化列表的构造函数:

    (1)成员类型是没有默认构造函数的类。若没有提供显示初始化式,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败。

    class Test1
    {
    public:
        Test1(int a):i(a){}//没有默认构造函数
        int i;
    };
    class Test2
    {
    public:
        Test1 test1 ;
        Test2(Test1 &t1)
        {test1 = t1 ;}
    };
    

    以上代码无法通过编译,因为Test2的构造函数中test1 = t1这一行实际上分成两步执行:

    调用Test1的默认构造函数来初始化test1

    由于Test1没有默认的构造函数,所以1 无法执行,故而编译错误。正确的代码如下,使用初始化列表代替赋值操作

    class Test1
    {
    public:
        Test1(int a):i(a){}        //没有默认构造函数
        int i;
    };
    class Test2
    {
    public:
        Test1 test1 ;
        Test2(int x):test1(x){}    //使用初始化列表
    }
    

    (2)const成员引用类型的成员。因为const对象或引用类型只能初始化,不能对他们赋值。

    #include <iostream>
    
    using namespace std;
    
    class A
    {
    public:
    #if 0
    	//因为成员变量中含有引用和常量则不能如此定义该构造函数
    	A(){
    		cout<<"aaaaaaaa"<<endl;
    	}
    #endif
    #if 1
    	A(int x1 = 0):x(x1),rx(x),pi(3.14) { }//带有初始化列表的默认构造函数
    	void print()
    	{
    		cout<<"x="<<x<<" rx="<<rx<<" pi="<<pi<<endl; 
    	}
    	~A(){}
    private:
    	int x;
    	int &rx;		 //声明为引用时则必须在构造函数基/成员初始值设定项列表中初始化
    	const double pi; //声明为const时则必须在构造函数基/成员初始值设定项列表中初始化
    #endif
    };
    
    int main()
    {
    	A a(20);
    	a.print();
    
    	A a1;		//因为A有默认构造函数,则可以如此调用
    	a1.print();
    
    	system("pause");
    	return 0;
    }
    

    注:如果一个构造函数为所以参数都提供默认实参,则它实际上也定义了默认构造函数

    (3)基类未声明默认构造函数

    #include <iostream>
    
    using namespace std;
    
    class Animal
    {
    public:
    	Animal(int weight,int height):        //基类未声明默认构造函数
    	m_weight(weight),m_height(height){
    		cout<<"Animal "<<"weight="<<weight<<" height="<<height<<endl;
    	}
    
    private:
    	int m_weight;
    	int m_height;
    };
    
    class Dog: public Animal
    {
    public:
    	Dog(int weight = 10,int height = 20,int type = 1):
    	  Animal(weight,height){//必须使用初始化列表增加对父类的初始化,否则父类Animal无合适构造函数
    		cout<<"Dog"<<endl;
    	}
    private:
    	int m_type;
    };
    int main()
    {
    	Dog d;
    
    	system("pause");
    	return 0;
    }
    

    最简单的解决方法是将Animal的构造函数声明默认构造函数:Animal(int weight = 0,int height = 0);

    4、初始化列表的成员初始化顺序:

    C++初始化类成员时,是按照声明的顺序初始化的,而不是按照出现在初始化列表中的顺序。

    class CMyClass {
        CMyClass(int x, int y);
        int m_x;
        int m_y;
    };
     
     CMyClass::CMyClass(int x, int y) : m_y(y), m_x(m_y){
    }
    

            你可能以为上面的代码将会首先做m_y=I,然后做m_x=m_y,最后它们有相同的值。但是编译器先初始化m_x,然后是m_y,,因为它们是按这样的顺序声明的。结果是m_x将有一个不可预测的值。有两种方法避免它,一个是总是按照你希望它们被初始化的顺序声明成员,第二个是,如果你决定使用初始化列表,总是按照它们声明的顺序罗列这些成员。这将有助于消除混淆。

            如果可以的话尽可能避免使用某些成员初始化其他成员。而最好用构造函数的参数作为成员的初始值,这样做的好处是可以比考虑成员的初始化顺序。例如以上可改为:

    class CMyClass {
         CMyClass(int x, int y);
         int m_x;
         int m_y;
     };
     
     CMyClass::CMyClass(int x, int y) : m_x(x), m_y(y) {
     }
    

     

    展开全文
  • 本文探讨C++构造函数体内初始化与列表初始化的区别: 结论是: 若某个类(下文的class B)有一个类成员是类类型(下文的class A),那么 1、若类B通过构造函数体内初始化,会先调用类A的默认构造函数(无参构造...

    本文探讨C++构造函数体内初始化与列表初始化的区别:
    结论是:
    若某个类(下文的class B)有一个类成员是类类型(下文的class A),那么
    1、若类B通过构造函数体内初始化,会先调用类A的默认构造函数(无参构造函数),再调用类A的赋值运算符;
    2、若类B通过初始化列表去初始化,则只调用类A的拷贝构造函数。
    另外,虽然对于成员类型是内置类型的情况,通过上述两种情况去初始化是相同的,但是为了标准化,推荐使用初始化列表。
    接下来,进入验证正题:
    下面分别陈列类A和类B的声明:

    class A {
    public:
    	A() {
    		cout << "A Default constructor" << endl;
    	}
    	A(int a) {
    		mA_a = a;
    		cout << "A constructor" << endl;
    	}
    	A(const A&) {
    		cout << "A copy constructor" << endl;
    	}
    	A& operator=(const A& a) {
    		cout << "A assign operator" << endl;
    		this->mA_a = a.mA_a;
    		return *this;
    	}
    	~A() {
    		cout << "A deconstructor" << endl;
    	}
    private:
    	int mA_a;
    };
    

    1.此时类B采用的是在构造函数内初始化:

    class B {
    public:
    	B() {
    		cout << "B Default Constructor" << endl;
    	}
    	B(A &a) {
    		cout << "come into B" << endl;
    		_a = a;
    		cout << "B Constructor" << endl;
    	}
    private:
    	A _a;
    };
    
    int main(){
    	A a;
    	B b(a);
    	return 0;
    }
    

    对应的输出为:
    在这里插入图片描述
    有图可得:
    第一行的“A Default constructor”是构造a调用的无参数构造函数。
    此处经过大佬点拨,再详细说明下
    第二行的“A Default constructor”是因为进入到类B对应的构造函数体内后,编译器首先会插入一些对成员变量的初始化,也就是编译器会隐形的对未初始化的成员变量进行默认初始化,这里类B有一个类型为类A的成员变量_a,那么初始化它的时候会调用类A的默认构造函数,所以会有第二个“A Default constructor”出现。再才是执行类B对应的构造函数的函数体,从而出现结果中的第3-5行的内容。所以,通过在构造函数体内初始化,首先会调用该成员的默认构造函数(无参构造函数,即结果中的第二行),然后再调用其赋值运算符。

    2.此时类B采用的是在初始化列表中初始化:

    class B {
    public:
    	B() {
    		cout << "B Default Constructor" << endl;
    	}
    	B(A &a) : _a(a){
    		cout << "come into B" << endl;
    		cout << "B Constructor" << endl;
    	}
    private:
    	A _a;
    };
    

    对应的输出为:
    在这里插入图片描述
    与第一种的输出相比,没有了赋值运算符“A assign operator”,也没有了第二个“A Default Constructor”,改变的是新添了“A copy constructor”。这是因为列表中的初始化操作先于函数体执行,而这里应该调用的便是拷贝构造函数。所以,通过初始化列表去初始化成员,只会调用该成员的拷贝构造函数(成员类型是某类类型)或者对应的构造函数(成员类型是内置类型)。

    总结:

    以下几种情况必须使用初始化列表去初始化类成员:

    • 当初始化一个reference member时,即成员类型是引用。
    • 当初始化一个const member时,即成员类型是常量。
    • 当调用一个基类的constructor,而它拥有一组参数时。如果此时不使用列表初始化,那么就需要自己重载赋值运算符。
    • 当调用一个类成员的constructor,而它拥有一组参数时。
    • 若某个类成员没有定义无参构造函数,而定义了其它的构造函数,也必须使用初始化列表。

    总之,为了标准化,建议使用列表初始化。不过小心一些陷阱:
    因为类成员的初始化顺序不是按照初始化列表的顺序来的,而是按照类成员的声明顺序,假如出现下列情况:

    class X {
    	int i;
    	int j;
    public:
    	X(int val) :j(val), i(j) {
    
    	}
    };
    

    由于类成员的初始化顺序是按照其声明顺序,故先初始化i,然而初始化列表中用j去初始化它,但是此时j并没有被初始化,所以会出错。

    展开全文
  • 1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员; 2.进入构造函数后在构造函数中执行一般赋值与计算。 使用初始化列表有两个原因: 原因1.必须这样做: 《C++ Primer》中提到在以下三种情况下需要使用...

    类对象的构造顺序是这样的:

    1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员;

    2.进入构造函数后在构造函数中执行一般赋值与计算。

    使用初始化列表有两个原因:

    原因1.必须这样做:

    《C++ Primer》中提到在以下三种情况下需要使用初始化成员列表:

       情况一、需要初始化的数据成员是对象的情况(这里包含了继承情况下,通过显示调用父类的构造函数对父类数据成员进行初始化); 

       情况二、需要初始化const修饰的类成员或初始化引用成员数据;

       情况三、子类初始化父类的私有成员;

     ■情况一的说明:数据成员是对象,并且这个对象只有含参数的构造函数,没有无参数的构造函数;

         如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。

    例子:

    1. #include “iostream”  
    2. using namespace std;  
    3. class Test  
    4. {  
    5.  public:  
    6.     Test (intintint){  
    7.     cout <<”Test” << endl;  
    8.  };  
    9.  private:  
    10.     int x;  
    11.     int y;  
    12.     int z;  
    13. };  
    14. class Mytest   
    15. {  
    16.  public:  
    17.     Mytest():test(1,2,3){       //初始化  
    18.     cout << ”Mytest” << endl;  
    19.     };  
    20. private:  
    21.     Test test; //声明  
    22. };  
    23. int _tmain(int argc, _TCHAR* argv[])  
    24. {  
    25.  Mytest test;  
    26.  return 0;  
    27. }  
    #include "iostream"
    using namespace std;
    class Test
    {
     public:
        Test (int, int, int){
        cout <<"Test" << endl;
     };
     private:
        int x;
        int y;
        int z;
    };
    class Mytest 
    {
     public:
        Mytest():test(1,2,3){       //初始化
        cout << "Mytest" << endl;
        };
    private:
        Test test; //声明
    };
    int _tmain(int argc, _TCHAR* argv[])
    {
     Mytest test;
     return 0;
    }
    

    输出结果:

    ①   如果没有mytest():test(1,2,3){}初始化列表就会报错:

    因为Test有了显示的带参数的构造函数,那么他是无法依靠编译器生成无参构造函数的,所以没有三个int型数据,就无法创建Test的对象。Test类对象是MyTest的成员,想要初始化这个对象test,那就只能用成员初始化列表,没有其他办法将参数传递给Test类构造函数。

    ②初始化列表在构造函数执行前执行(这个可以看上面的结果,对同一个变量在初始化列表和构造函数中分别初始化,首先执行参数列表,后在函数体内赋值,后者会覆盖前者)。

    ■情况二的说明:对象引用或者cosnt修饰的数据成员

         情况二:当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。

    例子:

    1. class Test  
    2. {  
    3.  priate:  
    4.     const int a;             //const成员声明  
    5.  public:  
    6.     Test():a(10){}           //初始化  
    7. };  
    8. 或  
    9. class Test  
    10. {  
    11.  private:  
    12.      int &a;                        //声明  
    13.  public:  
    14.      Test(int a):a(a){}        //初始化  
    15. }  
    class Test
    {
     priate:
        const int a;             //const成员声明
     public:
        Test():a(10){}           //初始化
    };
    或
    class Test
    {
     private:
         int &a;                        //声明
     public:
         Test(int a):a(a){}        //初始化
    }
    

    ■情况三的说明:子类初始化父类的私有成员,需要在(并且也只能在)参数初始化列表中显示调用父类的构造函数:如下:

     例子:

    1. class Test{  
    2. public:  
    3.     Test(){};  
    4.     Test (int x){ int_x = x;};  
    5.     void show(){cout<< int_x << endl;}  
    6. private:  
    7.     int int_x;  
    8. };  
    9. class Mytest:public Test{  
    10. public:  
    11.     Mytest() :Test(110){  
    12.       //Test(110);            //  构造函数只能在初始化列表中被显示调用,不能在构造函数内部被显示调用  
    13.     };  
    14. };  
    15. int _tmain(int argc, _TCHAR* argv[])  
    16. {  
    17.  Test *p = new Mytest();  
    18.  p->show();  
    19.  return 0;  
    20. }  
    class Test{
    public:
        Test(){};
        Test (int x){ int_x = x;};
        void show(){cout<< int_x << endl;}
    private:
        int int_x;
    };
    class Mytest:public Test{
    public:
        Mytest() :Test(110){
          //Test(110);            //  构造函数只能在初始化列表中被显示调用,不能在构造函数内部被显示调用
        };
    };
    int _tmain(int argc, _TCHAR* argv[])
    {
     Test *p = new Mytest();
     p->show();
     return 0;
    }

    结果:如果在构造函数内部被显示调用输出结果是:-842150451(原因是这里调用了无参构造函数);

                如果在初始化列表中被显示调用输出结果是:110

    原因2.效率要求这样做:

         类对象的构造顺序显示,进入构造函数体后,进行的是计算,是对成员变量的赋值操作,显然,赋值和初始化是不同的,这样就体现出了效率差异,如果不用成员初始化类表,那么类对自己的类成员分别进行的是一次隐式的默认构造函数的调用,和一次赋值操作符的调用,如果是类对象,这样做效率就得不到保障。

    注意:构造函数需要初始化的数据成员,不论是否显示的出现在构造函数的成员初始化列表中,都会在该处完成初始化,并且初始化的顺序和其在类中声明时的顺序是一致的,与列表的先后顺序无关,所以要特别注意,保证两者顺序一致才能真正保证其效率和准确性。

    为了说明清楚,假设有这样一个类:

    class foo

    {

     private:

       int a, b;

    };

    ①、foo(){}和foo(int i = 0){}都被认为是默认构造函数,因为后者是默认参数。两者不能同时出现。

    ②构造函数列表的初始化方式不是按照列表的的顺序,而是按照变量声明的顺序。比如foo里面,a在b之前,那么会先构造a再构造b。所以无论foo():a(b + 1), b(2){}还是foo():b(2),a(b+1){}都不会让a得到期望的值。

    ③构造函数列表能够对const成员初始化。比如foo里面有一个int const c;则foo(int x) : c(x){}可以让c值赋成x。

      不过需要注意的是,c必须在每个构造函数(如果有多个)都有值。

    ④在继承里面,只有初始化列表可以构造父类的private成员(通过显示调用父类的构造函数)。比如说:

    class child : public foo{};

    foo里面的构造函数是这样写的:

    foo (int x)

    {

      a =x;

    }.

    而在child里面写child(int x){ foo(x); }是通过不了编译的。

    只有把子类构造函数写作child(int x) : foo(x){}才可以。

                </div>
    
    展开全文
  • c++ 构造函数初始化过程

    千次阅读 2018-09-14 11:26:52
    每个类都会为它的对象定义初始化的方式,用一个或几个特殊的函数去控制对象的初始化,我们把这些特殊的函数叫做 构造函数。  那么,问题来了,构造函数作用是什么?  答:为了初始化对象的数据成员。就是简单。...
  • 文章目录C++中重载构造函数的互相调用初始化成员变量的问题不能直接互相调用的重载构造函数使用一个private的函数初始化成员变量使用带有默认参数的构造函数使用placement new运算符调用重载构造函数使用C++11的委托...
  • 深度学习之参数初始化(一)——Xavier初始化

    万次阅读 多人点赞 2017-06-10 18:28:19
    Understanding the difficulty of training deep ...本文介绍一下深度学习参数初始化问题中耳熟能详的参数初始化方法——Xavier(发音[‘zeɪvɪr])初始化。大家应该感觉到一般的深度学习文章上来就是实验,
  • 默认参数初始化列表

    千次阅读 2018-01-18 22:05:50
    1.构造函数的默认参数在声明时指定,(而不能只在定义构造函数时指定默认值)使得创建对象时,可以顺序缺省参数,使用默认参数初始化,例: class Box{ Box(int m = 10, int n= 20);//声明 } Box::Box(int m,...
  • 文章目录标准初始化方法形式激活值和梯度特性实验Xavier初始化形式满足Glorot条件的初始化激活值和梯度特性实验Xavier初始化的缺点 Understanding the difficulty of training deep feedforward neural networks by ...
  • 1. 类的静态成员变量不能用参数初始化初始化 (1) 如果声明了类而未定义对象,则类的一般数据成员是不占内存空间的,只有在定义对象时,在运行的时候才为对象的数据成员分配空间。但是静态数据成员不属于某一个...
  • 成员是类或结构,且构造函数参数:成员初始化时无法调用缺省(无参)构造函数  b. 成员是常量或引用:成员无法赋值,只能被初始化 2)从效率上:  如果在类构造函数里赋值:在成员初始化时会调用一次其默认...
  •   神经网络采用梯度下降的方法进行训练,在开始训练时需要对所有参数进行初始化初始化条件应满足均值为0,输入和输出的方差一致,不会进入激活函数的饱和区域。 1.标准初始化 标准均匀分布初始化方法: Wij∼N(0...
  • C++类构造函数初始化列表 构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。例如: class CExample { public:  int a;  float ...
  • 一、虚函数 ·虚表是怎么实现的?虚表存放在哪里? ·虚表中的数据是在什么时候确定的?... C++标准给编译器实现者定义了语法规范,但是并没有定义如何实现这些语法规范,不同的编译器实...
  • 神经网络参数的各种初始化算法

    千次阅读 2018-08-06 17:51:51
    基于不同的权重初始化方式初始化各层权重; b. 以直方图的形式查看每层输入给激活函数(线性运算后)的数据分布; 2. 正态分布初始化权重 a. 权重更新 weight = np.random.randn(in_node, out_node) 使用默认的...
  • 类的构造函数初始化成员时,有以下两种方式: 方式一: CSomeClass::CSomeClass()  {   x=0;   y=1;  }  方式二: CSomeClass::CSomeClass() : x(0), y(1)  {  }  方式一我们可以称为赋值初始化...
  • 其次,const一般不要修饰构造函数,因为这个修饰之后,构造函数里面的数据都不可以改变,这违背使用构造函数最初的目的了(为了赋值初始化) 转载原文地址: https://www.cnblogs.com/renzhuang/articles/661...
  • 如果使用的话,激活函数给神经元引入了非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络可以应用到众多的非线性模型中。 1. Sigmoid Sigmoid非线性函数的数学表达式是σ(x)=11+e−x\sigma (x)...
  • simulink自带模块非常多,但是内嵌函数会更灵活,自己写了一个关于一维数组kalman filter的算法,但是过年那会回家心不在焉的,随便写写了。回到学校发现有很大的BUG,输出结果不能用(其实在家发现了)。 在...
  • 一般我们进行成员变量初始化用两种方法 第一种是通过在构造函数内赋值 class Point { public:  Point(){ _x = 0; _y = 0;};  Point( int x, int y ){ _x = 0; _y = 0; } private:  int _x, _y; }; ...
  • 一、我的问题是关于初始化C++类成员的。我见过许多这样的代码: CSomeClass::CSomeClass() { x=0; y=1; } 而在别的什么地方则写成下面的样子: CSomeClass::CSomeClass() : x(0), y(1) { } 我的...
  • C++ 声明、定义、初始化与赋值

    千次阅读 2019-07-26 00:20:44
    一般我们进行成员变量初始化用两种方法 第一种是通过在构造函数内赋值 class Point { public: Point(){ _x = 0; _y = 0;}; Point( int x, int y ){ _x = 0; _y = 0; } private: int _x, _y; }; 第二种是...
  • Simulink中MATLAB Function的变量初始化

    千次阅读 2020-12-23 15:19:04
    MATLAB Function内部的M语言有严格的要求: 变量必须要给定初始值及其维度,变量类型及其虚实性,不支持变维度变量 simulink中的运行机制,每个采样点会调用一次MATLAB Function的函数,两次调用之间,同一个变量的...
  • java含参构造函数初始化

    千次阅读 2015-07-08 17:01:10
    是不是在创建对象时进入构造函数如果该类有继承关系根据Super()/Super(参数进入父类构造父类构造对象完成后按照初始化方法初始化子类对象(先初始化变量在初始化方法(包含构造方法))? ...
  • C++ Primer中在讲构造函数初始化列表的时候有这么一段话:  ...无论是在构造函数初始化列表中初始化成员,还是在...不同之处在于,使用构造函数初始化列表的版本初始化数据成员,没有定义初始化列表的构造函数版
  • Xavier初始化

    千次阅读 2019-04-26 20:07:32
    本文介绍一下深度学习参数初始化问题中耳熟能详的参数初始化方法——Xavier(发音[‘zeɪvɪr])初始化。 大家应该感觉到一般的深度学习文章上来就是实验,告诉读者这个实验结果好,然后由实验结果再反向给出一些...
  • 构造函数的成员初始化参数

    万次阅读 2011-04-26 21:25:00
    <br />构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。例如: class CExample {  public:  int a;  float b;...
  • 函数表存在的位置,初始化时机

    千次阅读 2014-09-22 15:05:15
    转zhttp://blog.csdn.net/lingfengtengfei/article/details/12345809 1.虚函数 ·虚表是怎么实现的?虚表存放在哪里?... C++标准给编译器实现者定义了语法规范,但是并没有定义如何实现这些语
  • C++使用初始化列表初始化数据成员的三种情况

    万次阅读 多人点赞 2018-08-11 15:04:27
    1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员(构造函数列表的初始化方式不是按照列表的的顺序,而是按照变量声明的顺序同时初始化显隐数据成员); 2.进入构造函数后在构造函数中执行一般赋值与计算。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 323,581
精华内容 129,432
关键字:

参数进入函数就被初始化了