精华内容
下载资源
问答
  • 静态成员变量只能在类外初始化
    2019-10-09 15:32:51

    文章目录


    静态成员变量是类对象所共有的成员变量,不应该依赖于实例对象的创建。类外定义静态成员变量就是一种很好的方法,保证只被初始化一次。
    static const int可以在类里面初始化,是因为它既然是const的,那程序就不会再去试图初始化了。
    1、避免重复初始化
    2、满足static语义

    #include   <iostream.h> 
    
    class   CDummy 
    { 
    public: 
            static   int   n; //这里只是声明
    }; 
    
    int   CDummy::n=9; //这里是定义加初始化
    
    void   main() 
    { 
            cout < <CDummy::n < <endl; 
    } 
    
    上面这样完全没问题,但是不能直接在类中初始化,比如: 
    
    static   int   n=9; 
    
    更多相关内容
  • C++类和对象(下)——初始化列表、static成员和友元

    千次阅读 热门讨论 2021-03-08 09:23:18
    C++类和对象——初始化列表、static成员和友元一、再谈构造函数1.1 构造函数整体赋值1.2 初始化列表三级目录 关于C++类和对象的学习 C++类和对象(上)——类的基本概念、类的限定符及封装和类成员函数的this指针 C++...


    关于C++类和对象的学习
    C++类和对象(上)——类的基本概念、类的限定符及封装和类成员函数的this指针
    C++类和对象(中)——类的6个默认成员函数(构造、析构、拷贝构造、赋值运算符重载)
    在这里插入图片描述

    一、再谈构造函数

    1.1 构造函数整体赋值

    在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。例如我们之前创建的Date类

    class Date
    {
    public:
    
    	Date(int year = 1900, int month = 1, int day = 1)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    

    虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称作为类对象成员的初始化,构造函数体中的语句只能将其称作为赋初值,而不能称作初始化因为初始化只能初始化一次,而构造函数体内可以多次赋值

    1.2 初始化列表

    <1>为什么有初始化列表?

    对于我们定义的日期类,当类中出现以下成员时,如果只用构造函数则无法完成变量的初始化了,以下的成员变量需要在定义的时候就需要初始化

    • 引用成员变量
    • const成员变量
    • 自定义类型的成员变量

    在这里插入图片描述
    其次对于自定义的类成员变量,不使用初始化列表会调用多次构造函数
    在这里插入图片描述

    <2> 如何使用初始化列表

    初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式
    注意:每个成员变量在初始化列表中只能出现一次

    //1.2.2
    class Time
    {
    public:
    	Time(int hour = 1, int minute=1,int second = 1)
    		:_hour(hour)
    		,_minute(minute)
    		,_second(second)
    	{
    		cout << "Time(int hour = 1, int minute=1,int second = 1)" << endl;
    	}
    private:
    	int _hour;
    	int _minute;
    	int _second;
    };
    
    class Date
    {
    public:
    	//初始化列表写法
    	Date(int year=1900, int month=1, int day=1,int hour=1,int minute=1,int second=1)
    		:_year(year)
    		,_month(month)
    		,_day(day)
    		,_n(10)
    		,_ref(day)
    		,_t(hour,minute,second)
    	{
    		cout << "Date(int year, int month, int day,int hour,int minute,int second)" << endl;
    
    	}
    
    private:
    	int _year;
    	int _month;
    	int _day;
    
    	//定义的时候需要初始化
    	int& _ref;	//引用
    	const int _n; //const成员变量
    	Time _t;	//自定义类型的成员变量
    };
    
    void Test2()
    {
    	Date d1(2021,3,9,2,2,2);
    }
    

    结果在这里插入图片描述

    <3> 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

    如下代码的运行结果是什么?

    //1.2.3
    class A
    {
    public:
    	A(int a)
    		:_a1(a)
    		, _a2(_a1)
    	{}
    	void Print() {
    		cout << _a1 << " " << _a2 << endl;
    	}
    private:
    	int _a2;
    	int _a1;
    };
    
    void Test2()
    {
    	A aa(1);
    	aa.Print();
    }
    

    结果

    在这里插入图片描述

    1.3 explicit关键字

    <1> 匿名对象

    匿名对象顾名思义就是没有名字,其作用域只在一行中有效,例如下面的代码

    //1.3.1
    class B
    {
    public:
    	B(int b = 0)
    		:_b(b)
    	{
    		cout << "B(int b = 0)" << endl;
    	}
    
    	//析构函数
    	~B()
    	{
    		cout << "~B()" << endl;
    	}
    private:
    	int _b;
    };
    
    int main()
    {
    	B bb(10);	//生命周期在main函数域
    	B(2);	//匿名对象生命周期在这一行
    	return 0;
    }
    

    在这里插入图片描述
    在这里插入图片描述

    <2> 为什么有explicit关键字?

    对于c++来说,构造函数不仅可以构造与初始化对象,对于单个参数的构造函数,还具有类型转换的作用

    当我们定义一个类进行初始化时,如果我们采取下面这种定义方式,编译器会自动生成一个匿名对象,然后用匿名对象对cc对象进行拷贝构造

    //1.3.2
    class C 
    {
    public:
    	C(int c)
    		:_c(c)
    	{
    		cout << "C()" << endl;
    	}
    
    private:
    	int _c;
    };
    
    int main()
    {
    	C cc(2);
    	cc = 8;	//编译器会自动生成一个匿名对象,然后用匿名对象对cc对象进行拷贝构造
    	return 0;
    }
    

    <3> 如何使用explicit关键字?

    用explicit修饰构造函数,将会禁止单参构造函数的隐式转换

    //1.3.3
    class C 
    {
    public:
    	explicit C(int c)
    		:_c(c)
    	{
    		cout << "explicit C(int c)" << endl;
    	}
    
    private:
    	int _c;
    };
    
    int main()
    {
    	C cc(2);
    	cc = 8;	//编译器会自动生成一个匿名对象,然后用匿名对象对cc对象进行拷贝构造
    	return 0;
    }
    

    在这里插入图片描述

    二、static成员

    2.1 概念

    声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化

    面试题:实现一个类,计算程序中创建出了多少个类对象?这个时候我们就可以使用static成员变量和static成员函数来实现

    //2.1 实现一个类,计算程序中创建出了多少个类对象。
    class A
    {
    public:
    	//构造函数
    	A()
    	{
    		++_scount;
    	}
    	//拷贝构造函数
    	A(const A& a)
    	{
    		++_scount;
    	}
    	
    	static int GetAcount()
    	{
    		return _scount;
    	}
    private:
    	static int _scount;
    };
    
    //初始化在类外
    int A::_scount = 0;
    
    void TestA()
    {
    	cout << A::GetAcount() << endl;
    	A aa;
    	A bb;
    	A cc(bb);
    	cout << A::GetAcount() << endl;
    }
    

    在这里插入图片描述

    2.2 特性

    <1> 静态成员为所有类对象所共享,不属于某个具体的实例

    <2> 静态成员变量必须在类外定义,定义时不添加static关键字

    在这里插入图片描述

    <3> 类静态成员即可用类名::静态成员或者对象.静态成员来访问

    在这里插入图片描述

    <4> 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

    在这里插入图片描述

    <5>静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值

    Q1: 静态成员函数可以调用非静态成员函数吗?

    不可以,因为静态成员函数没有隐藏的this指针

    Q2:非静态成员函数可以调用类的静态成员函数吗?

    可以,因为非静态成员函数含有this指针,指定了静态成员函数的类域
    在这里插入图片描述

    三、C++11的成员初始化新玩法

    3.1 为什么?

    对于C++98而言,类内自定义的内置类型,编译器会进行初始化,而其他内置类型不会,因此出现则会中初始化方法。
    具体查看这篇博客的2.2.7节内容
    C++类和对象(中)——类的6个默认成员函数(构造、析构、拷贝构造、赋值运算符重载)
    在这里插入图片描述

    3.2 怎么用?

    C++11支持非静态成员变量在声明时进行初始化赋值,但是要注意这里不是初始化,这里是给声明的成员变量缺省值

    //3.C++11的成员初始化新玩法
    class B
    {
    public:
    	B(int b = 0)
    		:_b(b)
    	{}
    	int _b;
    };
    class A
    {
    public:
    	void Print()
    	{
    		cout << a << endl;
    		cout << b._b << endl;
    		cout << p << endl;
    	}
    private:
    	// 非静态成员变量,可以在成员声明时给缺省值。
    	int a = 10;
    	B b = 20;
    	int* p = (int*)malloc(4);
    	//静态成员不可以
    	static int n;
    };
    int A::n = 10;
    
    int main()
    {
    	A a;
    	a.Print();
    	return 0;
    }
    

    在这里插入图片描述

    四、友元

    • 友元分为:友元函数友元类
    • 友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用

    4.1 友元函数

    问题:现在我们尝试去重载operator<<,然后发现我们没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以我们要将operator<<重载成全局函数。但是这样的话,又会导致类外没办法访问成员,那么这里就需要友元来解决。operator>>同理

    //4.1
    class Date
    {
    public:
    	Date(int year, int month, int day)
    		: _year(year)
    		, _month(month)
    		, _day(day)
    	{}
    	ostream& operator<<(ostream& _cout)
    	{
    		_cout << _year << "-" << _month << "-" << _day;
    		return _cout;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    int main()
    {
    	Date d(2017, 12, 24);
    	d << cout;
    	return 0;
    }
    

    在这里插入图片描述
    友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字

    //4.1
    class Date
    {
    friend ostream& operator<<(ostream& _cout, const Date& d);
    friend istream& operator >> (istream& _cin, Date& d);
    
    public:
    	Date(int year, int month, int day)
    		: _year(year)
    		, _month(month)
    		, _day(day)
    	{}
    	ostream& operator<<(ostream& _cout)
    	{
    		_cout << _year << "-" << _month << "-" << _day;
    		return _cout;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    ostream& operator<<(ostream& _cout, const Date& d)
    {
    	_cout << d._year << "-" << d._month << "-" << d._day << endl;
    	return _cout;
    }
    
    istream& operator >> (istream& _cin, Date& d)
    {
    	_cin >> d._year >> d._month >> d._day;
    
    	return _cin;
    }
    
    int main()
    {
    	Date d(2017, 12, 24);
    	cout<<d;
    	//Date d1;
    	cin >> d;
    	cout << d;
    	return 0;
    }
    

    在这里插入图片描述

    4.2 友元类

    友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

    • 友元关系是单向的,不具有交换性。
      比如下面Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
    • 友元关系不能传递
      如果B是A的友元,C是B的友元,则不能说明C时A的友元。
    class Date; // 前置声明
    class Time
    {
    	friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
    public:
    	Time(int hour=0, int minute=0, int second=0)
    		: _hour(hour)
    		, _minute(minute)
    		, _second(second)
    	{}
    private:
    	int _hour;
    	int _minute;
    	int _second;
    };
    
    class Date
    {
    public:
    	Date(int year = 1900, int month = 1, int day = 1)
    		: _year(year)
    		, _month(month)
    		, _day(day)
    	{}
    
    	void SetTimeOfDate(int hour, int minute, int second)
    	{
    		// 直接访问时间类私有的成员变量
    		_t._hour = hour;
    		_t._minute = minute;
    		_t._second = second;
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    
    	Time _t;
    };
    

    五、内部类

    概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。注意此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类。外部类对内部类没有任何优越的访问权限。

    注意:内部类就是外部类的友元类。注意友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

    特性:

    1. 内部类可以定义在外部类的public、protected、private都是可以的。
    2. 注意内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名。
    3. sizeof(外部类)=外部类,和内部类没有任何关系
    class A
    {
    private:
    	static int k;
    	int h;
    public:
    	class B
    	{
    	public:
    		void foo(const A& a)
    		{
    			cout << k << endl;//OK
    			cout << a.h << endl;//OK
    		}
    	};
    };
    int A::k = 1;
    int main()
    {
    	A::B b;
    	b.foo(A());
    	return 0;
    }
    
    展开全文
  • 类和对象对象的构造及初始化

    千次阅读 多人点赞 2022-03-29 12:39:22
    一篇教你对象的构造方法以及初始化


    🍛 如何初始化对象

    我们知道再Java方法内部定义一个局部变量的时候,必须要初始化,否则就会编译失败
    image.png
    要让这串代码通过编译,很简单,只需要在正式使用a之前,给a设置一个初始值就好
    那么对于创造好的对象来说,我们也要进行相对应的初始化
    我们先写一个Mydate的类

    public class MyDate {
    
        public int year;
        public int month;
        public int day;
    
        /**
         * 设置日期:
         */
        public void setDate(int year,int month,int day) {
            this.year = year;
            this.month = month ;
            this.day = day;
        }
    
        public void printDate() {
            System.out.println("年:"+this.year+"月:"+this.month+"日:"+this.day);
        }
       public static void main(String[] args) {
    
            // this.printDate();
    
            MyDate myDate = new MyDate();
    
            myDate.setDate(2022,3,25);
    
            myDate.printDate();
    
            MyDate myDate2 = new MyDate();
    
            myDate2.setDate(2022,3,28);
            myDate2.printDate();
    
        }
    }
    

    我们可以看到,在Mydate类中,要在调用之前实现写好setDate才能将具体的日期设置到对象当中
    image.png
    我们通过这个例子就可以发现两个问题:

    1. 每次对象创建好之后调用setDate方法设置具体时期,比较麻烦,那么对象该如何初始化呢?
    2. 局部变量必须要初始化之后才能使用,那么为什么字段声明之后没有给初值,它依旧可以使用呢?

    答案:

    1. 我们可以运用构造函数来进行初始化
    2. 因为这里和main函数中定义的局部变量不同,编译器会自动为你的字段声明的局部变量赋初始零值。

    🍱 构造方法

    当我们实例化一个对象的时候:必须会有这两步,但并不是一定只有这两步

    1. 为对象分配内存
    2. 调用合适的构造方法

    构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象的时候,由编译器自动调用,并且在整个对象的生命周期内只调用一次

    class Person {
        public String name;
        public int age;
    
        //构造方法:
        //名字与类名相同,且没有返回值类型,void也不行
        //一般情况下使用public修饰
        //在创建对象的时候由编译器自动调用,并且在对象的声明周期内只调用一次
        public Person(String name,int age){
            this.name = name;
            this.age = age;
            System.out.println("构造方法被调用了")
        }
        public void eat() {
            System.out.println("吃饭!");
        }
    
        public void sleep() {
            System.out.println("睡觉!");
        }
        public static void main(String[] args){
            //在此处创建了一个Date类型的对象,并没有显式调用构造函数
            Person p = new Person("xiaohong",18);
            p.eat();
        } 
    }
    

    ⚠️:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间
    image.png

    🍕 特性

    1. 名字必须和类名相同
    2. 没有返回值类型,void也不行
    3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生)
    4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
    class Student {
        //属性:成员变量-》类的内部  方法的外部的
        public String name;
        public int age;
        public double score ;
        public String sex;
    
    
        public Student() {
            //调用本类中   带有2个参数的构造方法,第一个参数的类型是String,第2个参数的类型是int
            this.age = 18;
            System.out.println("这个是不带参数的构造方法!");
        }
    
        public Student(String name,int age) {
            //this();
            this.age = age;
            this.name = name;
            System.out.println("这个是带2个参数的构造方法!");
        }
    
        public Student(String name, int age, double score, String sex) {
            this.name = name;
            this.age = age;
            this.score = score;
            this.sex = sex;
            System.out.println("带4个参数的构造方法!");
        }
    
        public void doClass() {
            System.out.println(name+"正在上课!");
            //this.doHomeWork();
        }
        public void doHomeWork(){
            System.out.println(name+"正在写作业");
        }
    
        public void show() {
            System.out.println("姓名:"+name+" 年龄:"+age+" 学分:"+score+" 性别:"+sex);
        }
    }
    //重载的时候
    

    上述方法中:名字相同,参数列表不同,因此构成了方法重载
    如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。

    class MyGirlFired {
        public String name;
        public int age;
        public String eyes;
    
        public void eat() {
            System.out.println("吃火锅!");
        }
    }
    

    在上面的代码中,没有定义任何构造方法,编译器就会默认为我们生成一个不带参数的构造方法
    ⚠️:一旦用户定义了,编译器则不再生成任何构造函数
    image.png

    class MyGirlFired {
        public String name;
        public int age;
        public String eyes;
    
        public MyGirlFired(String name,int age){
            this.name = name;
            this.age = age;
        }
        public void eat() {
            System.out.println("吃火锅!");
        }
    
        public static void main(String[] args) {
            //如果编译器会生成,则生成的构造方法一定是无参数的
            //则此处创建对象是可以通过编译的
            //但实际上会报错
            MyGirlFired xHong = new MyGirlFired();
        }
    }
    

    image.png
    在构造方法中,可以通过this调用其他构造方法来简化代码

    class Student {
        //属性:成员变量-》类的内部  方法的外部的
        public String name;
        public int age;
        public double score ;
        public String sex;
    
    
        public Student() {
            //调用本类中   带有2个参数的构造方法,第一个参数的类型是String,第2个参数的类型是int
            this("yumi",18);
            //this("bit3",99,98.9,"女");
            System.out.println("这个是不带参数的构造方法!");
        }
    
        public Student(String name,int age) {
            //this();
            this.age = age;
            this.name = name;
            System.out.println("这个是带2个参数的构造方法!");
        }
    
        public Student(String name, int age, double score, String sex) {
            this.name = name;
            this.age = age;
            this.score = score;
            this.sex = sex;
            System.out.println("带4个参数的构造方法!");
        }
    
        public void doClass() {
            System.out.println(name+"正在上课!");
            //this.doHomeWork();
        }
        public void doHomeWork(){
            System.out.println(name+"正在写作业");
        }
    
        public void show() {
            System.out.println("姓名:"+name+" 年龄:"+age+" 学分:"+score+" 性别:"+sex);
        }
    }
    

    ⚠️注意:

    • this()必须是构造方法中的第一条语句,且只能放在构造函数中
    • 不能形成“环”

    例如
    image.png
    绝大多数情况我们都用public来修饰,特殊场景下会被private修饰

    🌭默认初始化

    上面我们提到了一个问题:为什么局部变量在使用时必须要用初始化,而成员变量可以不用呢?

    public class Date {
        public int year;
        public int month;
        public int day;
        
        public Date(int year,int month,int day){
            //成员变量在定义之前,并没有给出初始值,那为什么就可以使用呢?
            System.out.println(this.year);
            System.out.println(this.month);
            System.out.println(this.day);
        }
    
        public static void main(String[] args) {
            //此处a并没有初始化,编译器报错;
            //Error:(24,28)Java:可能尚未初始化变量a
            //int a;
            //System.out.println(a);
            Date d = new Date(2022,3,29);
        }
    }
    

    image.png
    要搞清楚这个过程,我们需要知道new关键字背后所发生的一些事情

    Date d = new Date(2021,6,9);
    

    在程序层面只是简单的一条语句,而在JVM层面则需要做好多事情

    1. 检测对象对应的类是否加载了,如果没有加载则加载
    2. 为对象分配内存空间
    3. 处理并发安全问题

    👉比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突

    1. 初始化所分配的空间

    即:对象空间被申请好了之后,对象中包含的成员已经设置好了初始值
    image.png

    数据类型默认值
    byte0
    char‘\u0000’
    short0
    int0
    long0L
    booleanfalse
    float0.0f
    double0.0
    referencenull
    1. 设置对象头信息(关于对象内存模型后面再说)
    2. 调用构造方法,是给对象中的各个成员赋值

    🍤就地初始化

    在声明成员变量时,就直接给出了初始值

    public class Date {
        public int year;
        public int month;
        public int day;
    
        public Date(){
            System.out.println(this.year);
            System.out.println(this.month);
            System.out.println(this.day);
        }
        public Date(int year,int month,int day){
            //成员变量在定义之前,并没有给出初始值,那为什么就可以使用呢?
            System.out.println(this.year);
            System.out.println(this.month);
            System.out.println(this.day);
        }
    
        public static void main(String[] args) {
            //此处a并没有初始化,编译器报错;
            //Error:(24,28)Java:可能尚未初始化变量a
            //int a;
            //System.out.println(a);
            Date d1 = new Date(2022,3,29);
            Date d2 = new Date();
        }
    }
    
    
    //运行结果:
    //0
    //0
    //0
    //0
    //0
    //0
    
    

    ⚠️注意:代码编译完成之后,编译器会将所有成员初始化的这些语句添加到各个构造函数中
    image.png
    image.png
    5.一个类至少会有1个构造函数,就算你没有写!
    6.构造方法 本质 就是来实例化对象的时候调用
    (1)分配内存
    (2)调用合适的构造方法
    7.this可以用来调用本类中的其他构造方法【构造方法当中使用】
    且必须放在第一行!所以,只能在当前构造方法当中,调用一次
    8.this的用法:

    • this.data 访问属性
    • this.func(); 访问方法
    • this(); //用来调用本类中的其他构造方法

    9.this不能形成环。

    有错误请大家批评指正
    感谢阅读

    展开全文
  • c++类成员初始化方式

    万次阅读 多人点赞 2019-07-11 18:59:33
    转载自: ...常用的初始化可能如下: 1)赋值初始化 class Student { public: Student(string in_name, int in_age) { name = in_name; age = in_age; } private : string...

    转载自:
    https://blog.csdn.net/coder_xia/article/details/7447822

    常用的初始化可能如下:

    1)赋值初始化

    class Student 
    {
    public:
    	Student(string in_name, int in_age)
    	{
    		name = in_name;
    		age = in_age;
    	}
    private :
    	string name;
    	int    age;
    };
    

    可以达到预期效果,不过不是最佳做法,因为在构造函数中,是对name进行赋值,不是初始化,而string对象会先调用它的默认构造函数,再调用string类(貌似是basic_string类)的赋值构造函数,产生了临时对象,速度慢;对于上例的age,因为int是内置类型,应该是赋值的时候获得了初值。

    要对成员进行初始化,而不是赋值,可以采用初始化列表(member initialization list)改写为如下:

    2)初始化列表

    class Student 
    {
    public:
    	Student(string in_name, int in_age):name(in_name),age(in_age) {}
    private :
    	string name;
    	int    age;
    };
    

    结果与上例相同,不过在初始化的时候调用的是string的拷贝构造函数,而上例会调用两次构造函数,**在分配内存空间时直接初始化,**从性能上会有不小提升

    有的情况下,是必须使用初始化列表进行初始化的:const对象、引用对象

    3)初始化列表初始顺序

    考虑以下代码:

    #include <iostream>
    using namespace std;
     
    class Base 
    {
    public:
    	Base(int i) : m_j(i), m_i(m_j) {}
    	Base() : m_j(0), m_i(m_j) {}
    	int get_i() const
    	{
    		return m_i;
    	}
    	int get_j() const
    	{
    		return m_j;
    	}
     
    private:
    	int m_i;
    	int m_j;
     
    };
     
    int main()
    {
    	Base obj(98);
    	cout << obj.get_i() << endl << obj.get_j() << endl;
        return 0;
    }
    

    输出为一个随机数和98,为什么呢?

    因为对于初始化列表而言,对成员变量的初始化,是严格按照声明次序,而不是在初始化列表中的顺序进行初始化,如果改为赋值初始化则不会出现这个问题,当然,为了使用初始化列表,还是严格注意声明顺序吧,比如先声明数组大小,再声明数组这样。

    类对象的构造顺序:

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

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

    以下三种情况下需要使用初始化成员列表:

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

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

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

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

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

    例子:

    #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对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
    

    例子:

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

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

    例子:

    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;
    };
    
    展开全文
  • 有一个类A,其数据成员如下: class A { ... private: int a; public: const int b;...则构造函数中,成员变量一定要通过初始化列表来初始化的是...构造函数中,成员变量一定要通过初始化列表来初始化的有以下几种...
  • C++成员初始化列表

    千次阅读 2018-12-16 14:20:38
    C++类成员初始化列表C++类型定义C++构造函数的初始化列表定义C++构造函数执行的两个阶段为什么使用初始化列表C++里面哪些东西必须放在初始化列表里面成员变量的初始化顺序 这边文章主要学习C++里面的成员初始化列表...
  • 1 静态数据成员不能用参数初始化表对静态数据成员初始化 (1) 如果声明了类而未定义对象,则类的一般数据成员是不占内存空间的,只有在定义对象时,才为对象的数据成员分配空间。但是静态数据成员不属于某一个对象...
  • c++类的成员变量初始化总结

    千次阅读 2019-06-14 17:04:11
    首先把需要初始化成员变量分为几类: a.一般变量(int) b.静态成员变量(static int) c.常量(const int) d.静态常量(static const int) 对应的初始化方式是: a.一般变量可以在初始化列表里或者构造...
  • C++之数据成员初始化

    千次阅读 2019-05-16 13:24:33
    类数据成员初始化,这份工作主要是构造函数负责的,构造函数的职责之一就是对数据成员进行正确初始化。实际上,构造函数的执行过程主要有两个阶段: (1)初始化阶段 (2)普通计算阶段 初始化阶段是指对数据...
  • Java成员变量的初始化

    千次阅读 2017-02-23 22:30:39
    Java中成员变量的初始化 类变量与成员变量
  • 结论:对于类的const成员只能使用初始化列表,而不能在构造函数内部进行赋值操作。原因如下:1、构造函数不能被声明为const函数,因此当我们创建一个类的const对象时,直到构造函数完成初始化的过程,对象才真正...
  • 类的成员变量的初始化顺序

    千次阅读 2018-09-03 11:34:43
    类的成员变量的初始化顺序只与变量在类中的声明顺序有关,与在构造函数中的初始化列表顺序无关。 注意:是与声明顺序有关。 #include&lt;iostream&gt; using namespace std; class A { public: //我们...
  • C++类成员变量初始化顺序问题

    千次阅读 多人点赞 2016-07-19 20:17:35
    今天在看剑指offer这本书时,看待一个简单的举例,说应聘C++岗位的不知道成员变量初始化顺序!我很惊讶,因为我也不知道,所以就看上网查了一下,看到了一个博客()以及其中的内容,现在将我的学习过程分享出来! ...
  • 对象的构造顺序是这样的: 1.分配内存,调用构造函数时,隐式/显示的初始化各数据... 情况一、需要初始化的数据成员对象的情况(这里包含了继承情况下,通过显示调用父类的构造函数对父类数据成员进行初始化);
  • 成员初始化列表

    千次阅读 2017-03-18 17:44:29
    2、成员初始经列表由逗号分隔的初始化列表组成(前面带冒号)。它位于参数列表的右括号之后、函数体左括号之前。 3、初值可以是常量或构造函数的参数列表中的参数。这种方法并不限于初始化常量。 例如下代码: Queue:...
  • 构造函数初始化时必须... (常量成员)需要初始化const修饰的类成员 3. (引用)需要初始化引用成员数据class A { ... private: int a; }; class C{ C(int b); }; class B : public A { ... private: int a;...
  • C++类中成员变量的初始化总结一

    千次阅读 2019-09-01 22:02:40
    考虑一下效率的可以再构造函数的初始化列表中进行。 class CA { public: int data; …… public: CA(); …… }; CA::CA():data(0)//……#1……初始化列表方式 { //data = 0;//……#1……赋值...
  • 1、类成员为const类型2、类成员为引用类型究其因const对象或引用只能初始化但是不能赋值。构造函数的函数体内只能赋值而不是初始化,因此初始化const对象或引用的唯一机会是构造函数函数体之前的初始化列表中。从无...
  • 数据成员必须在构造函数初始化列表中初始化: 没有默认构造函数的内嵌对象引用类型的数据成员常数据成员
  • 必须使用【初始化列表】初始化数据成员的情况 类对象的构造顺序是这样的: 1.分配内存,调用构造函数时,隐式/显示的初始... 情况一、需要初始化的数据成员对象的情况(这里包含了继承情况下,通过显示调用父类的...
  • C++中类的数据成员如何初始化

    千次阅读 2020-03-10 18:25:10
    C++中类的数据成员初始化,首先需要明白在类中都有哪些数据成员 const成员:也就是常量成员,它们在声明时就要初始化,因为它们为常量成员,一旦定义,就不能修改 引用成员&:引用代表的就是被引用者自身,是...
  • C++继承、成员访问权限
  • 对象的构造顺序是这样的: 1.分配内存,调用构造函数时,隐式/显示的初始化各数据... 情况一、需要初始化的数据成员对象的情况(这里包含了继承情况下,通过显示调用父类的构造函数对父类数据成员进行初始化);
  • C++静态成员变量的初始化

    千次阅读 2018-06-19 07:52:28
    class example{ public: //static double rate=6.5;...1,类内成员在被定义时是不能被初始化的,只能通过构造函数来进行初始化。 2,类内静态变量的初始化方式是先在类内定义,再到类外面进行初始化
  • 在C++中,如果没有在构造函数初始值列表中显示地初始化成员,则该成员将在构造函数体之前执行默认初始化。之后,再进入构造函数体{}中,随着构造函数体一开始执行,初始化地工作实际上就完成了。 下面两个构造函数...
  • C++ 类中的static成员初始化和特点

    千次阅读 2018-08-23 09:34:44
    C++ 类中的static成员初始化和特点 在C++的类中有些成员变量初始化和一般数据类型的成员变量有所不同。以下测试编译环境为: ➜ g++ -v Using built-in specs. COLLECT_GCC=g++ Target: x86_64-linux-gnu gcc ...
  • 类的成员变量初始化总结

    万次阅读 2015-04-08 11:52:23
    首先把需要初始化成员变量分为几类: Ø 一般变量(int) Ø 静态成员变量(static int) Ø 常量(const int ) Ø 静态常量(static const int)  对应的初始化方式是: Ÿ 一般变量可以在初始化列表里或者...
  • C++静态成员变量初始化和赋值

    万次阅读 2019-03-07 14:29:57
    有这样一套会话机制,CSession为会话对象,CSessionManager为会话管理类,在CSession会话需要销毁时,CSession主动发送消息给CSessionManager销毁session。同时CSession是一个基类,子类通过继承CSession实现不同的...
  • 为了初始化成员属性,而不是初始化对象初始化对象通过new关键字实现的  2.通过new调用构造方法初始化对象,编译时根据参数签名来检查构造函数,称为静态联编和编译多态  (参数签名:参数的类型,参数个数和...
  • C++使用初始化列表初始化数据成员的三种情况

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

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 310,094
精华内容 124,037
关键字:

对象成员只能通过初始化