您的位置:首页 > 移动开发 > Objective-C

20161230C++阶段班03_Object C++_03构造函数/命名空间/初始化列

2017-01-11 17:24 113 查看

构造函数精讲:

1:构造函数:

    是一个特殊的成员函数,一般情况下为public:在一些特定的情况下可能会为private:这会导致我们无法新建对象。  构造函数会被自动调用,确保我们能够正常的初始化,使我们构造函数保证的功能。如果没写构造函数, 会默认自动生成。构造函数可以重载。但是如果自己写了任意一个构造函数,就不会自动生成默认的构造函数了。

2:#pragma once防止头文件被二次编译(多次包含),这个是windows编译器所特有的,不支持跨平台。一般还是使用#ifndef,#define,#endif比较好。

把上面的 #parag once改成 

 #ifndef _CLASSDEMO_H_

#define _CLASSDEMO_H_

#endif//!_CLASSDEMO_H_

3:#include<>和#include""的区别:

    <>先引用的是编译器的类库路径里面的头文件,""引用的是自己程序目录的相对路径中的头文件,如果里面没有,他还是会在对应的引用目录查找这个头文件(一般系统头文件用<>,自己写的头文件用"")。如果自己写的库名字与系统的一样(eg:stdio.h),那就必须使用""才可以调用自己写的库了。

4:命名空间:

    可以把类写在一个命名空间里面。这样会不重名。using namespace PoEdu;//表示直接开放PoEdu里面所有的代码。但一般不要这样用。可能会导致命名空间污染,最好不要全部开放。用那些就开放那些。否则他可能不知道调用哪一个命名空间里面的函数。命名空间是用来区分组织的,不同公司写的库里面很可能有重名的函数,所以有命名空间来区分这些组织。在一个函数里面,全部开放还好,但最好不要把他开放到全局中。很容易导致命名空间污染。命名空间作用域只在本cpp文件或者库文件类。出了文件就得重新定义。

5:可文件包含库:

    #include""在被包含的时候会被展开,如果头文件里面也包含有很多库,就会导致编译变慢。头文件里面最好不要包含很多库,系统级的库可以包含在里面问题不大。cpp里面可以包含比较多都没问题。如果库函数里面要使用自己写的类,也不用包含那个类的头文件,可以直接在前面做前置申明即可。做前置申明后,后面的数据要做成指针或者引用。总之不能再头文件里面包含过多自己写的头文件。

6:初始化类成员可以初始化成指针,也会调用构造函数,但是要手动delete才会调用析构函数。

#include <iostream>
#include "ClassDemo.h"

int main()
{
using namespace PoEdu;
ClassDemo demo;
ClassDemo demo1(10);
std::cout << demo.GetNum() << std::endl;//随即数据
std::cout << demo1.GetNum() << std::endl;//10

ClassDemo *demop = new ClassDemo;//也会调用构造函数
ClassDemo *demop1 = new ClassDemo();//也会调用默认构造函数
ClassDemo *demop2 = new ClassDemo(20);//调用带参构造函数
delete demop;//以指针申请的类成员需手动删除才可以
delete demop1;
delete demop2;

ClassDemo array[10];//会调用10次无参的析构函数
ClassDemo array1[10] = { 1 };//会调用1次有参的构造函数,9次无参的析构函数
ClassDemo array2[10] = { 1, 2, 3 };//会调用3次有参的构造函数,7次无参的析构函数

ClassDemo *pArray = new ClassDemo[10];//会调用无参10次
delete[]pArray;//一定要加[],否则删除会出错。

ClassDemo *demo2 = static_cast<ClassDemo*>(malloc(sizeof(ClassDemo)));
//不会调用构造函数,malloc只能单纯的申请内存空间。必须使用new才可以开辟类指针的正确方式。
free(demo2);

return 0;
}


7:转换构造函数:

    重载的构造函数中只有一个参数的时候(或则第二个参数后面的全部有默认值,只需要传递第一个参数)就会自动提升成为转换构造函数。申请类成员的时候直接使用等号就可以:

ClassDemo demo = 10;//这个等号不是赋值,而是提升为转换构造函数了。也会调用构造函数。
ClassDemo demo1 = static_cast<char>(0x31);
//ClassDemo demo1 = 'c';//字符等其他类型都可以!
赋值函数为:
demo = 20;//这种成为赋值函数。


    但执行这个的时候会执行新的构造函数,生成一个临时对象,同时又调用析构函数。而且是临时对象的析构函数。就为了传递一个参数。没写构造函数和析构函数,系统会默认生成,同时还默认生成了赋值函数的。与下面的类似。

classDemo& classDemo::operator=(const classDemo& other)
{
//拷贝全部参数。
return *this;//返回本身。
}
    像demo = 20这种赋值,就会默认用20用转换构造函数生成一个临时对象(前提是有适合的转换构造函数),然后调用上面的方法对对象拷贝。也可以将两个对象直接相等就是直接调用这个赋值函数。相当于对整个对象的值赋值为另一个对象的值。默认的赋值函数只能适用于本类型之间的对象赋值。上面能成功是因为C++有隐式转换,利用转换构造函数把20构造成一个对象。然后赋值的!

    也可以自己重载这个默认的赋值函数。重载了可以传递整型,字符型等数据类型的参数。自己重载这个函数后,默认的函数并不会消失。他还是会有默认的(这里与构造函数和析构函数不一样)。

    可不可以使用ClassDemo demo = 10;只取决于有没有对应的转换构造函数(前提是对应的转换函数前面没有加explicit),与赋值完全无关。能否使用demo = 20;取决于要么有对应的转换构造函数(前提是对应的转换函数前面没有加explicit),要么自己重载了赋值函数!如果两个条件都达到,默认会调用自己重载的赋值函数,而不会隐式转换。

    explicit关键字:只作用于构造函数。抑制构造函数的隐式转换。在构造函数前面加上explicit的时候,这个构造函数就不能提升为转换构造函数了,只能按默认的方式来用这个构造函数申请对象,不能直接用=号了。

    总结:1:如果没有写任何一个构造函数,会生成默认的构造函数(无需传参的)

                   1.1:如果写了任何一个,都不会在生成。

                   1.2:只需要传递一个参数的构造函数会提升为转换构造函数,用于隐式转换。

                           TEST t = int;//隐式转换不是赋值,而是转换构造函数。

                           默认的赋值函数  接收的参数是当前类的对象引用。

初始化列表:

classDemo(int num):_num(num),_other(num)//称为初始化列,直接就赋值了
{
_num = num; _other = num;//称为计算列
}//


上面的和括号里面的区别在于:

    初始化列表为:int _num = num; int_other = num;

    括号里面的相当于:int _num; _num = num; int _other; _other = num;

    最大的问题不在于提高效率,而是类里面的数据如果是const的话,就必须用上面那种才可以,相当于初始化的时候就赋值了。不光是const,引用也是必须在初始化的时候赋值,只能用上面那种。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  编程