精华内容
下载资源
问答
  • 对类对象成员的初始化是通过
    千次阅读
    2022-04-15 10:08:24

    1.类初始化顺序

    当类初始化的时候,会调用其构造函数并进行初始化。当对象结束其生命周期,会调用析构函数进行资源回收。

    注意类在调用资深构造函数之前,首先会调用其成员变量构造函数并进行初始化,再进入自身构造函数进行初始化。成员变量的声明顺序,就是初始化顺序。后面我们提到的很多情况就跟这个有关系,后面再进行详细解读。

    2.声明时初始化

    第一种方式是在成员变量声明时初始化。可以看如下示例。

    class D {
        int a = 10;
    };
    

    在声明变量a的时候即给其初始化为10。不过注意这种写法是c++11以后才有的。上述代码在IDE中会有如下警告信息:

    in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions]
    

    3.构造函数初始化列表

    第二种方式是在构造函数中加入一个初始化列表,对成员变量进行初始化。

    class D {
        int a, b;
        string c;
        public:
            D() : a(1), b(2), c("sss") {
                cout<<"a is: "<<a<<endl;
                cout<<"b is: "<<b<<endl;
                cout<<"c is: "<<c<<endl;
            }
    };
    

    如果我们对D进行实例化,

    int main(int argc, char const *argv[])
    {
        D d;
        return 0;
    }
    

    代码会有如下输出

    a is: 1
    b is: 2
    c is: sss
    

    4.构造函数内部赋值

    在其他语言中,比如java,最常用的方式为在构造函数内部赋值。

    class D {
        int a, b;
        string c;
        public:
            D(int a, int b, string c) {
                this->a = a;
                this->b = b;
                this->c = c;
                cout<<"a is: "<<a<<endl;
                cout<<"b is: "<<b<<endl;
                cout<<"c is: "<<c<<endl;
            }
    };
    
    int main(int argc, char const *argv[])
    {
        D d(1, 2, "sss");
        return 0;
    }
    

    上面代码输出为

    a is: 1
    b is: 2
    c is: sss
    

    5.只能构造函数初始化列表的情况

    如果一个类成员,他本身是一个类或者结构,而且这个类成员没有默认的无参构造函数,只有带参数的构造函数,这个时候对类成员初始化时,必须调用类成员带参数的构造函数。如果再初始化列表中没有完成类成员初始化,代码会报错。

    };
    
    class F {
        E e;
        public:
            F() {cout<<"init F class!"<<endl;}
    };
    
    int main(int argc, char const *argv[])
    {
        F f;
        return 0;
    }
    

    上述代码是可以正常运行的,因为类E有默认无参构造函数。

    而如果将代码改为下面的样子,给E加一个带参数的构造函数

    class E {
        int num;
        public:
            E(int n) {
                this->num = n;
            }
    };
    
    class F {
        E e;
        public:
            F() {cout<<"init F class!"<<endl;}
    };
    
    int main(int argc, char const *argv[])
    {
        F f;
        return 0;
    }
    

    上面代码在IDE里直接会报错:

    constructor for 'F' must explicitly initialize the member 'e' which does not have a default constructor
    

    此时需要将F的构造函数改成如下形式:

    class F {
        E e;
        public:
            F() : e(10) {cout<<"init F class!"<<endl;}
    };
    

    另外,如果类的成员变量中有const时候,也需要在成员初始化列表中赋值完成初始化。

    class F {
        private:
            const int num;
        public:
            F(): num(10) {}
    };
    

    比如上面类F中有一个const常量num,就需要再F构造函数列表中对其进行赋值,否则代码会报错。

    6.列表初始化与构造函数初始化区别

    当采用列表初始化的时候,代码直接调用了成员变量的构造函数,只需要一步就可以完成。
    而在构造函数中初始化的时候,先调用的是成员变量的默认构造函数构造了类成员,然后再调用赋值运算符对之前默认构造的类成员进行赋值,这实际上进行了两步操作。
    当类的结构较为复杂的时候,会存在性能上的差异。

    更多相关内容
  • 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;
    }
    
    展开全文
  • 【C++】构造函数 利用构造函数对类对象进行初始化

    千次阅读 多人点赞 2022-01-25 16:01:26
     前言: 因为类对象的数据成员的值是很重要的 而对类对象数据成员初始化这一重要而频繁的操作 当然越简便越好 所以这里讲的就是对对象数据成员初始化的一些方法 9.1.1 对象的初始化 1. 在声明时直接数据成员...

    7个月之后的补充: 说真的,别再收藏这篇文章了,写的真的很拉跨,建议学习并收藏C++ 六个默认成员函数 + this指针_CPP的底层是哲学的博客-CSDN博客

    也是我写的,质量会好很多!!!!!! 

    前言:

    因为类对象的数据成员的值是很重要的 而对类对象数据成员初始化这一重要而频繁的操作 当然越简便越好 所以这里讲的就是对对象数据成员初始化的一些方法

    9.1.1 对象的初始化

    1. 在声明类时直接对数据成员进行初始化 如下所示

    在某红书中说到 在声明类时对数据成员初始化是不对的 但是在 c++11标准下 是允许在声明类时 对数据成员直接赋初值的 因为这本书比较落后了 所以内容没有更新 在vs2019中 这种方法是没有报错的 但是注意考试的时候要填不能在声明类时直接对数据成员赋初值

    2. 把数据成员声明为公用成员

    把数据成员声明为公用成员后 在定义对象时 可以像定义结构体变量那样对数据成员初始化 但是绝大多数情况下 数据成员都不会声明为公用的 所以这种方法并不可取

    9.1.2 用构造函数实现数据成员的初始化

    c++提供了构造函数来处理对象的初始化

    ①  用户不能调用构造函数,在建立对象时自动执行,且只能执行一次。一般声明为public

    ②  构造函数是在声明类的时候由类的设计者定义的,程序用户只须在定义对象的同时指定数据成员的初值即可。

    ③  构造函数名必须和类名同名,不能随意命名。

    ④  构造函数不具有任何类型,不具有返回值。 可以有参数。

    ⑤  可以用一个类对象初始化另一个类对象 如 Time t1;  Time t2 = t1;  这样就把t1的各数据成员的值复制到t2相应的各成员 而不调用t2的构造函数Time();

    ⑥  构造函数的函数体中还可以包含如cout的其他语句 但是不推荐这样做

    ⑦  如果类的定义者没有自己定义构造函数,则c++系统会自动形成一个构造函数,这个构造函数函数体是空的,没有参数,不执行任何操作。

    class Time
    {
    public:
    	Time()
    	{
    		hour = 0;
    		minute = 0;
    		sec = 0;
    	}
    	void set_time();
    	void show_time();
    private:
    	int hour;
    	int minute;
    	int sec;
    };
    
    void Time::set_time()
    {
    	cin >> hour >> minute >> sec;
    }
    
    void Time::show_time()
    {
    	cout << hour << ":" << minute << ":" << sec << endl;
    }
    
    int main()
    {
    	Time t1;
    	t1.set_time();
    	t1.show_time();
    	Time t2;
    	t2.show_time();
    	return 0;
    }

    这是构造函数的一个很简单的运用 这里的构造函数的功能是 给对象的数据成员赋初值为0  建立对象t1时调用构造函数  对象t1再调用了set_time函数 重新赋了一次值  而t2中的数据成员的值都是0

    构造函数同样可以在类内声明  在类外定义  同样需要声明构造函数的所属类 以及作用于限定符  即

    9.1.3  带参数的构造函数

    引:上方给出的构造函数,是十分死板的。每个建立的对象都有同样的初始化值,无法达到不同对象不同初始化值的效果。所以有了带参数的构造函数。

    即构造函数的参数列表中加若干参数 并在函数体中对不同数据成员赋值。 这样在建立对象并执行构造函数时,就可以把定义对象时给的一些数据赋给数据成员。

    构造函数的实参只能在定义对象时给出,即建立对象的同时给出数据成员的初值。

    // 带参数的构造函数
    class Cube
    {
    public:
    	int volume();
    	Cube(int, int, int);
    private:
    	int length;
    	int width;
    	int height;
    };
    Cube::Cube(int a, int b, int c)
    {
    	length = a;
    	width = b;
    	height = c;
    }
    int Cube::volume()
    {
    	return length * width * height;
    }
    int main()
    {
    	//Cube c1 = { 10,20,30 };		
    	Cube c1(10, 20, 30);   	//建立对象c1 并指定c1的长宽高  直接在后面加括号就行;
    	cout << "c1的体积为:" << c1.volume() << endl;
    	Cube c2(10, 10, 10);
    	cout << "c2的体积为:" << c2.volume() << endl;
    	return 0;
    }

    带参数的构造函数的声明以及类对象的定义方法如上所示,注意main函数中第一行第二行的方式都可以, 第二种可以看成给构造函数的形参赋实参。类似于函数调用。

     9.1.4  用参数初始化表对数据成员初始化

    不在构造函数函数体内执行初始化语句,放在函数首部实现。让构造函数显得简短精炼,就可以在类体内定义构造函数而不在类外定义。尤其当数据成员较多时更显其优越性,许多c++程序人员都喜欢用这种方式初始化所有数据成员。

    // 参数初始化表对数据成员初始化
    #include<string.h>
    class cube
    {
    public:
    	cube(int l, int w, int h,string n) :length(l), width(w), height(h) ,name(n)  //参数初始化表
    	{
    		//strcpy(arr, brr);
    	}
    	void show();
    private:
    	int length;
    	int width;
    	int height;
    	//char arr[10];
    	string name;
    };
    
    void cube::show()
    {
    	cout << name << ":" << length * width * height << endl;
    }
    int main()
    {
    	cube c1(10, 20, 30, "yang");
    	c1.show();
    	
    	cube c2(10, 10, 10, "li");
    	c2.show();
    	return 0;
    }

    格式如上,即: 在构造函数的函数首部后方再加一个冒号后面给出对应的值 

    注意:对于数组的初始化不可以像其他数据那样 因为数组不可以直接用等于号赋值(string可以)需要用strcpy这样的字符数组操作函数进行初始化。 

    9.1.5  构造函数的重载

    即多个构造函数同名,但参数的个数不同,或参数的类型不同的构造函数。称为构造函数的重载

    class Box
    {
    public:
    	int volume();
    	Box(int l, int w, int h) :length(l),width(w),height(h){}  //有三个参数的构造函数
    	Box(int l,int w):length(l),width(w)                       //有两个参数的构造函数
    	{
    		height = 10;
    	}
    	Box(int l) :length(l)									  //有一个参数的构造函数
    	{
    		width = 10;
    		height = 10;
    	}
    	Box();													  //无参构造函数
    private:
    	int length;
    	int width;
    	int height;
    };
    
    int Box::volume()
    {
    	return length * height * width;
    }
    
    Box::Box()
    {
    	length = 10;
    	width = 10;
    	height = 10;
    }
    
    int main()
    {
    	Box b1;
    	cout << "b1的体积为:" << b1.volume() << endl;
    	Box b2(20, 20, 20);
    	cout << "b2的体积为:" << b2.volume() << endl;
    	Box b3(20, 20);
    	cout << "b3的体积为:" << b3.volume() << endl;
    	Box b4(20);
    	cout << "b4的体积为:" << b4.volume() << endl;
    	return 0;
    }

    9.1.6  使用默认参数的构造函数 

    构造函数中参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值。

    class cube
    {
    public:
    	cube(int l = 10, int w = 10, int h = 10):length(l),width(w),height(h){}
    	void show();
    private:
    	int length;
    	int width;
    	int height;
    };
    
    void cube::show() 
    {
    	cout << "length=" << length <<"  " << "width=" << width <<"  " << "height=" << height << endl;
    }
    
    int main()
    {
    	cube c1(20, 20, 20);
    	c1.show();
    	cube c2(20, 20);
    	c2.show();
    	cube c3(20);
    	c3.show();
    	cube c4;
    	c4.show();
    	return 0;
    }
    
    

    可以看到,在构造函数中使用默认参数是方便而有效的,它提供了建立对象时的多种选择,它的作用相当于好几个重载的构造函数。它的好处是:即使在调用构造函数时没有提供实参值,不仅不会出错,而且还确保按照默认的参数值对对象进行初始化。尤其在希望对每一个对象都有同样的初始化状况时用这种方法更为方便,不需输人数据,对象全按事先指定的值进行初始化。

    注意:


    (1)在建立对象时不必给出实参的构造函数,称为默认构造函数( defaultconstructor)。显然,无参构造函数属于默认构造函数。一个类只能有一个默认构造函数。如果用户未定义构造函数,则系统会自动提供一个默认构造函数,但它的函数体是空的,不起初始化作用。如果用户希望在创建对象时就能使数据成员有初值,就必须自己定义构造函数。

    (2)  应该在什么地方指定构造函数的默认参数?应在声明构造函数时指定默认值,而不能只在定义构造函数时指定默认值。因为类声明是放在头文件中的,它是类的对外接口,用户是可以看到的,而函数的定义是类的实现细节,用户往往是看不到的。(类声明和类定义会放在两个文件中)。在声明构造函数时指定默认参数值,使用户知道在建立对象时怎样使用默认参数。

    (3)程序第5行在声明构造函数时,形参名可以省略,即写成Box ( int = 10 , int = 10 , int = 10);

    (4)如果构造函数的全部参数都指定了默认值,则在定义对象时可以给一个或几个实参,也可以不给出实参。由于不需要实参也可以调用构造函数,因此全部参数都指定了默认值的构造函数也属于默认构造函数。前面曾提到过:一个类只能有一个默认构造函数,也就是说,可以不用参数而调用的构造函数,一个类只能有一个。其道理是显然的,是为了避免调用时的歧义性。

    (5)在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。自行理解为什么

    (6)  但如果构造函数中的参数并非全部为默认值时,(即部分指定默认值)就要分析具体情况。不是一定会出错,是很容易出错,要十分仔细。因此,一般不应同时使用构造函数的重载和有默认参数的构造函数。

    总结:

    (上方6点是我复制的= =) 构造函数,就是一个在对象建立时自动执行的函数,作用就是方便给对象的数据成员赋初值。 核心就是有参数的构造函数以及有默认参数的构造函数。 我认为这种是最方便的,在建立对象时可直接指定该对象的数据成员的值。

    析构函数

    析构函数是与构造函数作用相反的函数  当对象的生命期结束时,会自动执行析构函数。

    析构函数不返回任何值,没有函数类型,也没有函数参数。由于没有函数参数,因此它不能被重载。一个类可以有多个构造函数,但是只能有一个析构函数。
    实际上,析构函数的作用并不仅限于释放资源方面,它还可以被用来执行“类的设计者希望在最后一次使用对象之后所执行的任何操作”,例如输出有关的信息。

    如果用户没有定义析构函数,C++编译系统会自动生成一个析构函数,但它只是徒有析构函数的名称和形式,实际上什么操作都不进行。想让析构函数完成任何工作,都必须在定义的析构函数中指定。

     调用构造函数和析构函数的顺序

    一般情况下: 先构造的后析构,后构造的先析构。

     构造函数和析构函数在面向对象的程序设计中是相当重要的,是类的设计中的一个重要部分。

    展开全文
  • 会先创建Stu,对象成员,然后再创建banji 然而我们如果在Banji的构造函数里面初始化Stu,那就来不及了! 这时候,我们应该使用初始化列表! 因为初始化列表在构造函数的函数体执行顺序之前! 能够在初始...

    demo.cpp

    #include<iostream>
    #include"Banji.h"
    using namespace std;
    int main()
    {
    	Banji b;
    	system("pause");
    	return 0;
    }

    Student.h

    class Student
    {
    	public:
    		Student();
    		~Student();
    		void setNum(int x);
    		int getNum();
    	private:
    		int m_iNum;
    };

    Banji.h

    #include"Student.h" 
    class Banji
    {
    	public:
    		Banji();
    		~Banji();
    		int setStu(int x);
    		int getStu();
    	private:
    		Student stu;
    };

    Student.cpp

    #include"Student.h"
    #include<iostream>
    using namespace std;
    		Student::Student()
    		{
    			cout<<"Student"<<endl;
    		}
    		Student::~Student()
    		{
    			cout<<"~Student"<<endl;
    		}
    		void Student::setNum(int x)
    		{
    			m_iNum=x;
    		}
    		int Student::getNum()
    		{
    			return m_iNum;
    		}

    Banji.cpp

    	#include"Banji.h"
    	#include<iostream>
    	using namespace std;
    	Banji::Banji()
    	{
    		cout<<"Banji()"<<endl;
    	}
    		Banji::~Banji()
    		{
    			cout<<"~Banji()"<<endl;
    		}
    
    		int Banji::setStu(int x)
    		{stu.setNum(x);}
    		int Banji::getStu()
    		{return stu.getNum();}

    大家运行起来是没有问题的。

    然后我现在改一下

    如果我们的Student这个类的构造函数需要参数呢?

    更改后的代码如下

    demo.cpp

    #include<iostream>
    #include"Banji.h"
    using namespace std;
    int main()
    {
    	Banji b(3);
    	system("pause");
    	return 0;
    }

    Student.h

    class Student
    {
    	public:
    		Student(int x);
    		~Student();
    		void setNum(int x);
    		int getNum();
    	private:
    		int m_iNum;
    };

    Banji.h

    #include"Student.h" 
    class Banji
    {
    	public:
    		Banji(int x);
    		~Banji();
    		int setStu(int x);
    		int getStu();
    	private:
    		Student stu;
    };

    Student.cpp

    #include"Student.h"
    #include<iostream>
    using namespace std;
    		Student::Student(int x)
    		{
    			m_iNum=x;
    			cout<<"Student"<<endl;
    		}
    		Student::~Student()
    		{
    			cout<<"~Student"<<endl;
    		}
    		void Student::setNum(int x)
    		{
    			m_iNum=x;
    		}
    		int Student::getNum()
    		{
    			return m_iNum;
    		}

    Banji.cpp

    	#include"Banji.h"
    	#include<iostream>
    	using namespace std;
    	Banji::Banji(int x)
    	{
    		Stu(x);
    		cout<<"Banji()"<<endl;
    	}
    		Banji::~Banji()
    		{
    			cout<<"~Banji()"<<endl;
    		}
    		int Banji::setStu(int x)
    		{
    			stu.setNum(x);
    		}
    		int Banji::getStu()
    		{
    			return stu.getNum();
    		}


    你会发现,会报bug

    为什么呢?

    这是因为我们要知道,我们创建banji类的时候,

    会先创建Stu,对象成员,然后再创建banji

    然而我们如果在Banji的构造函数里面初始化Stu,那就来不及了!

    这时候,我们应该使用初始化列表!

    因为初始化列表在构造函数的函数体执行顺序之前!

    能够在初始化Banji之前初始化Stu!

    改法:


    banji.cpp里面

    Banji::Banji(int x):stu(x)
    {
    cout<<"Banji()"<<endl;
    }

    展开全文
  • C++ 类对象初始化

    千次阅读 2021-04-13 20:50:08
    与c语言不同,在面向对象的编程中,使用构造函数数据成员进行初始化,有多种方式。 录: 一、无参数的构造函数 二、带参数的构造函数 三、使用构造函数的参数初始化表 四、带默认参数的构造函数 各种方式的描述...
  • 摘要:在C++11之后,声明时初始化->初始化列表->构造函数初始化
  • python面向对象——类成员初始化方法

    千次阅读 多人点赞 2020-03-20 17:28:10
    中创建了成员后,可以通过类的实例进行访问 实例方法 是指在中定义的函数。该函数是一种在的实例上操作的函数。 ‘’‘ 语法: class 类名(): 的说明信息 def 方法名(self,参数1,参数2,): 方法体 ...
  • 组合 指针和类对象初始化

    千次阅读 2020-10-23 16:40:15
    的组合 构造函数的用法 在一个中内嵌另一个的对象作为数据成员,称为的组合。该内嵌对象称为对象成员...在使用过程中,需要着重注意的是对象成员初始化!如Triangle的构造函数该如何定义? 如果一个具...
  • 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...
  • 对象对象的构造及初始化

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

    千次阅读 2022-04-16 22:11:22
    目录 1. 默认初始化 2.零初始化 3.值初始化 4.直接初始化 ...5.复制初始化 ...6.聚合初始化 ...自动:局部变量,非静态数据成员 这些类型的初始化行为可以分为以下几种: 1. 默认初始化 语法: T obj; ne
  • 【C++】利用构造函数对类对象进行初始化

    千次阅读 多人点赞 2018-10-06 21:02:00
    运行环境:VS2017 一、对象初始化 每一个对象都应当在它建立之时就有就有确定的内容,否则就会失去对象的意义。...如果一个是公用的,可以在定义对象数据成员进行初始化。 class Time ...
  • 利用构造函数对类对象进行初始化

    千次阅读 2018-01-27 17:53:00
    是一个实体,不能在声明中数据成员初始化; 2.可以像结构体一样,在定义对象的时候用花括号初始化 3. c++提供了构造函数来处理对象的初始化。构造函数是特殊的成员函数,它不需要用户来调用,而是在建立对象...
  • C++ 类对象初始化顺序

    千次阅读 2018-05-16 17:02:58
     基类构造函数如果有多个基类,则构造函数的调用顺序是某派生表中出现的顺序而不是它们在成员初始化表中的顺序;4. 成员类对象构造函数如果有多个成员类对象,则构造函数的调用顺序是...
  • 成员变量的初始化顺序

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

    万次阅读 多人点赞 2018-11-02 21:13:24
    如何给中定义了带有参数的构造函数的对象数组赋值 class A { public: A(){}//无参构造函数0 A(int i){}//有参构造函数1 A(int i,int j){}//有参构造函数2 }; int main() { A a,b[5];//调用6次无参构造函数...
  • c++成员变量初始化总结

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

    千次阅读 2020-03-29 17:03:50
    还有一些仍旧是类初始化。由于可能存在C++11支持的程度不同,以及编译器厂商是否C++进行了扩展。下面是我的测试平台: 测试环境 Windows 10的64位操作系统 Microsoft Visual Studio Community 2019 ...
  • JAVA笔记-初始化对象初始化

    千次阅读 2016-06-26 13:19:24
    初学Java,觉得初始化对象初始化这一块真的特别重要,翻了很多大神前辈的整理资料,还是有些懵懂,决定将资料整理下,也希望后来的初学者有些许帮助。 上图为的生命周期 看到 方法时,有些懵懂,...
  •  (C++11提供了初始化,因此内常量可在声明时进行初始化,因此该内常量的作用域属于级,即该的所有对象均具有同一个值。)#include &lt;iostream&gt; using namespace std; class A ...
  • 那么当构造函数在内实现的时候,一般构造函数的函数体仅仅是起到对类的私有数据成员进行初始化的作用。 这次就小小的总结一下,当构造函数在内实现的时候,两种不同的对类的私有数据成员初始化方式。 以点...
  • 对象定义以及四种初始化方式

    千次阅读 2018-04-26 22:10:31
    实体的一种抽象,也可以看做是一种模板,对象则是使用模板制造的多个实物 我们如果把人看做是一个(Person) 那么人有他自己的名字,年龄,性别等,这些是人的属性 但是人也可以吃饭,睡觉,玩游戏等,有...
  • 我们知道C++的静态成员变量是需要初始化的,但为什么要初始化呢。其实这句话“静态成员变量是需要初始化的”是有一定问题的,应该说“静态成员变量需要定义”才是准确的,而不是初始化。两者的区别在于:初始化是...
  • 对象初始化

    千次阅读 2018-06-03 17:26:29
    本文主要通过例子来理解 Java 中对象初始化顺序问题
  • Java中成员变量的初始化过程

    千次阅读 2021-03-09 17:45:24
    Java中的成员变量分为两种:第一种是成员变量,第二种是...1.没有被修饰符修饰的成员变量和局部变量的初始化在java中所有的成员变量都会被系统赋予默认是初始值,这个初始值根据不同的数据类型有着不同的定义:Bool...
  • 测试: #include #include #include #include #include #include #include using namespace std; class member1{ public: member1(){ cout !" ; } ~membe
  • C++ 未初始化类成员变量

    千次阅读 2020-03-31 09:42:46
    初始化类成员变量 在gcc 4.8.5版本 如果还有未初始化类成员变量,其值不确定
  • 【C++】中静态成员的声明、初始化类中静态成员的声明初始化静态数据成员值的改变完整例子 有参考大佬 零点零一 的文章:https://blog.csdn.net/thanklife/article/details/78476737 中静态成员的声明 中的静态...
  • C++派生中如何初始化基类对象

    千次阅读 2018-08-26 16:41:42
    关于派生中如何初始化基类对象,我在想派生对于构造函数不都是先构造基类对象,然后在构造子类对象,但是如果我们在成员初始化列表先初始化派生的私有成员,在函数内去调用基类的构造函数,能编译通过吗?...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 602,873
精华内容 241,149
热门标签
关键字:

对类对象成员的初始化是通过