QT C++学习one day

1.命名空间:

在c++中,名称可以是符号常量、变量、函数、结构、枚举、类和对象等等。工程越大,名称互相冲突性的可能性越大。另外使用多个厂商的类库时,也可能导致名称冲突。为了避免,在大规模程序的设计中,以及在程序员使用各种各样的C++库时,这些标识符的命名发生冲突,标准C++引入关键字namespace(命名空间/名字空间/名称空间),可以更好的控制标识符的作用域。

1.1命名空间使用语法

创建一个命名空间

//定义一个名字为A的命名空间(变量、函数)

namespace A {

变量 int a

函数

}

A中的a A::a  a是属于A的

命名空间是在函数外定义的,只能全局范围内定义,局部定义是错误的

1.2命名空间可以嵌套命名空间

命名空间是开放的,即可以随时把新成员加入已有的命名空间中

1.3:命名空间可以存放变量和函数,可以存放到类里面,可以存放到结构体里面。

2.4:命名空间中的函数可以在外边定义。

无名命名空间,意味着命名空间中的标识符只能在本文件内访问,相当于给这个标识符加上了static,使得其可以作为内部连接

1.4:给命名空间取别名

namespace veryLongName {
    int a=10;
    void func()
    {
         cout << "Hello namespace" << endl;
    }
}
 
  
void test()
{
    namespace shortName =veryLongName;
 
  
    cout << "veryLongName::a=" << shortName::a < 
  
    veryLongName::func();
    shortName::func();
}
int main()
{
    test();
   // test2();
   // test01();
    //test3();
   // test05();
    int num=0;
    cin >>num;
    cout << "num =" < 
  
    cout << "Hello World!" << endl;
 
  
    char buf[128]="";
    strcpy(buf,"Hello string");
    cout << buf < 
  
    return 0;
}

1.5using使用命名空间

//指明 使用命名空间中的具体成员

using namespace veryLongName::a;

cout << "a=" << a <

//using直接使用 命名空间中的成员会和局部变量冲突,不会和全局变量冲突

但是使用func时,必须加作用域

1.6using 遇到重载函数

总结

1、命名空间的定义(不能再函数内定义命名空间)

2、使用命名空间的成员最安全的方式  命名空间::成员名

3.using namespace 命名空间名:使用整个命名空间

using namespace A;

4、单独使用命名空间中的具体成员:using 命名空间::成员名

using A::a

在C语言代码中,声明不开辟空间,定义才开辟空间

c语言不允许在结构体中定义成员函数

C++语言,允许在结构体中定义成员函数

const修饰的全局变量,默认是内部链接(只在当前源文件有效,不能直接用于其他源文件

//如果必须用在其他源文件 使用只读的全局变量

二、two day

1.1c语言全局const会被存储到只读数据段。C++中全局const当声明extern或者对变量取地址时,编译器会分配存储地址,变量存储在只读数据段,两个都受到了只读数据段的保护,不可修改。

总结:

1、const int data =10; //data先放入符号表

2、如果对data取地址 系统才会给data开辟空间

3、const int a=b;//b是变量名,系统直接给a开辟空间而不放入符号表

4、const修饰自定义数据,系统为自定义数据开辟空间

2、宏的作用域是整个文件,const的作用域已定义情况决定。

问题:宏定义可以有命名空间嘛?

const和#define区别总结

1、const有类型,可进行编译器类型安全检查。#define无类型,不可进行类型检查

2.const有作用域,而#define 不重视作用域,默认定义处到文件结尾。如果定义在指定作用域下有效的常量,那么#define就不能用。

1。宏常量没有类型,所以调用了int类型重载的函数。const有类型,所以调用希望的short类型函数?

C++能用引用绝对不用指针

C++增加了一种给函数传递地址的途径,这就是按引用传递,它也存在与其他一些编程语言中

变量名实质上是一段连续内存空间的别名

引用可以作为一个已定义变量的别名。基本语法:Type&ref=val;&在此不是求地址运算,而是起标识作用

语法:

1、&和别名结合表示引用

2、给某个变量取别名就定义某个变量

3.从上往下替换

int num = 10;

int &a=num;//此处&不是取地址,int a = &b,这才是取地址

注意:

1.引用必须初始化

2、引用一旦初始化,就不能再次修改别名

知识点【引用作为函数的返回值】

给函数的返回值取别名

1、函数返回啥变量,引用就是该变量的别名

2、函数的返回值是引用时,不要返回局部变量

3.函数的返回值为左值,为引用

三、three

//1.C++中对于基础类型系统不会给data开辟空间,data放到符号表中

//2、C++中当对data取地址的时候,系统就会给data开辟空间

3、当以变量的形式初始化const修饰的变量系统会为其开辟空间

4、const自定义数据类型(结构体、对象)系统会分配空间

const和#define区别总结:

1.const有类型,可进行编译器类型安全检查。#define无类型,不可进行类型检查

2.const有作用域,而#define不重视作用域,默认定义处到文件结尾如果定义在指定作用域下有效的常量,那么#define就不能用。

四、内联函数(inline function)

在C中我们经常把一些短并且执行频繁的计算写成宏,而不是函数,这样做的理由是为了执行效率,宏可以避免函数调用的开销。

内联函数为了继承宏函数的效率,没有函数调用时开销,然后又可以像普通函数那样,可以进行参数,返回值类型的安全检查,又可以作为成员函数。

4.1内联函数基本概念

在c++中,预定义宏的概念是用内联函数来实现的,而内联函数本身也是一个真正的函数。内联函数具有普通的所有行为。唯一不同之处在于内联函数会在适当的地方像预定义宏一样展开,所以不需要函数调用的开销。因此应该不使用宏,使用内联函数。在普通函数(非成员函数)函数前面加上inline关键字使之成为内联函数。但是必须注意函数体和声明结合在一起,否则编译器将它作为普通函数来对待。inline void func(int a);以上写法没有任何效果,仅仅是声明函数,应该如下方式来做:inline int func(int a){return ++;}注意:编译器将会检查函数参数列表

三、threeday

class和struct的区别

class默认是私有的

struct默认是公有的

3.1将成员变量设置为private

a.可赋予客户端访问数据的一致性。如果成员变量不是public,客户端唯一能够访问对象的方法就是通过成员函数。如果类中所有public权限的成员都是函数,客户在访问类成员时只会默认访问函数,不需要考虑访问的成员需不需要添加{}。

b.可细微划分访问控制。使用成员函数可使得我们对变量得控制处理更加精细。如果我们让所有得成员变量为public,每个人都可以读写它。如果我们设置为private,我们可以实现“不准访问”、“只读访问”、读写访问“,甚至你可以写出”只写访问“。

class默认是私有得 数据私有 方法公有,用户就可以借助公有方法间接得操作

知识点一:在类内声明,类外定义成员函数

知识点二:【类的定义在头文件,成员函数是在cpp文件中】

如果定义一个类class MyString ,它的头文件为mystring.h,他的c++文件为mystring.cpp

四、对象的构造和析构

4.1当对象销毁之前应该销毁自己创建的一些数据。对象的初始化和清理也是两个非常关键的主要问题,一个对象或者变量没有初始化时  ,对其使用后果是未知,同样的使用完一个变量,没有及时清理,也会造成一定的安全问题,构造函数和析构函数,这两个函数将会被编译器自动调用,完成对对象初始化和对象清理工作。无论你是否喜欢,对象的初始化和清理工作是编译器强制我们要做的事情,即使你不提供初始化操作和清理操作,编译器也会给你增加默认的操作,只是这个默认初始化操作不会做任何事,所以编写类就应该顺便提供初始化函数。为什么初始化操作是自动调用而不是手动调用?既然是必须操作,那么自动调用会更好,如果靠程序员自觉,那么就会存在遗落初始化的情况出现。

4.2构造函数和析构函数的概述

造函数和析构函数,这两个函数将会被编译器自动调用,构造函数完成对象的初始化动作,析构函数在对象结束的时候完成清理工作。

注意:对象的初始化和清理工作是编译器强制我们要做的事情,即使你不提供初始化操作和清理操作,编译器也会给你增加默认的操作,只是这个默认初始化操作不会做任何事。

4.3构造函数和析构函数

构造函数主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。析构函数主要用于对象销毁前系统自动调用,执行一些清理工作。构造函数函数名和类名相同,没有返回值,不能有void,但可以有参数,能重载。ClassName(){}

析构函数语法:析构函数函数名是在类名前面加“~”组成,没有返回值,不能有void,不能有参数,不能重载。~ClassName(){}

构造函数:实例化对象的时候系统自动调用

析构函数:对象释放的时候系统自动调用

知识点1【构造函数和析构函数定义】


class Data
{
public:
    int num;

public:
    //构造函数(无参构造)
    Data()
    {
        num=0;
        cout << "无参的构造函数" << endl;
    }
    //有参的构造
    Data(int n)
    {
        num=n;
        cout<<"有参的构造" <

    }

    //析构函数
    ~Data()
    {
        cout <<"析构函数" << endl;
    }

};

void test1(void)
{
    //Data();
    //类实例化对象 系统自动调用构造函数
    Data ob;
    //函数结束的时候 ,局部变量ob被释放,系统自动调用析构函数
}
int main()
{
    cout <<"----------001_--------"< test1();

cout << "-______-------002---------"<     return 0;
}

知识点三【构造函数的分类以及调用】

1、构造函数分类

按参数类型:分为无参构造函数和有参构造函数

按类型分类:普通构造函数和拷贝构造函数(复制构造函数)

1.1匿名对象(当前语句结束 匿名对象立即释放)

在同一作用域下,构造函数和析构函数的顺序相反

//调用拷贝构造函数(如果用户不实现拷贝构造,系统将调用默认的拷贝构造)

//默认的拷贝构造:单纯的整体赋值(

Data ob2(ob1);      //隐式调用拷贝构造函数

Data ob3 =Data(ob1);        //显示调用拷贝构造函数

Data ob4 = ob1;    //=隐式转换调用

记住一句话:旧对象 初始化   新对象        才会调用拷贝构造函数

Data ob1(10);

Data ob2 (ob1);         //拷贝构造

Data  ob3 = Data(ob1);  //拷贝构造

Data ob4 = ob1;        //拷贝构造函数

注意:下方的就不会调用拷贝构造

Data ob1(10);

Data ob2;

ob2 = ob1;

知识点7【构造函数的调用规则】

系统会对任何一个类提供3个函数成员函数:

1、默认构造函数(空)默认析构函数(空)默认拷贝构造函数(浅拷贝)

五、深拷贝和浅拷贝

5.1浅拷贝

同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况被称为浅拷贝。一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动态内存释放的处理,会导致内存问题。

5.2深拷贝

调用拷贝构造函数就不会调用有参构造函数,调用有参构造函数,就不会调用无参构造函数

六、初始化列表(参数列表)

构造函数和其他函数不同,除了名字,参数列表,函数体之外还有初始化列表。初始化列表简单使用:

六、类的对象作为另一个类的成员

七、【explicit】

C++提供了关键字explicit,禁止通过构造函数进行的隐式转换,声明为explicit的构造函数不能在隐式转换中使用。

八、【new和delete】从堆区申请空间

1、malloc、calloc、realloc比较

1.1malloc(calloc、realloc)返回一个void指针,C++不允许将void赋值给其他任何指针,必须强转

1.2、malloc(calloc/realloc)可能申请内存失败,所以必须判断返回值来确保内存分配成功

1.3、malloc(calloc、realloc)不会调用构造函数。free不会调用析构函数(重要的)

2、new申请基本类型数组

p=new int;

3、给类对象申请空间

Person *p=new Person();

知识点十:对象数组

元素是类的对象,本质是数组

Person arr1[5];     //对象数组,arr1是数组,每个元素是Person类型的对象

//定义对象数组的时候,系统会自动给数组中的每个元素调用构造函数

//自动调用无参构造

如果想让对象数组中的元素调用有参构造,必须认为使用有参构造初始化

new 按照Person申请空间 如果申请成功,就会自动调用Person类的构造函数

delete先调用析构函数,再释放堆区空间

//第一种方式

Person *arr = NULL;

arr = new Person[5];        //调用无参构造

delete 【】arr;

Person *arr2 = new Person【5】{Person(“Lucy”,18)};

void指针可以储存任意类型的指针

2、尽量不用delete去释放void *;否则没有析构函数

为什么呢

void*没有析构函数,系统不知道释放多大的空间

delete发现p1指向的类型为void,无法从void中寻找析构函数

九、静态成员(static)

静态成员包括静态变量和静态函数

static修饰的静态成员,被其他对象共享。

static声明为静态的,称为静态成员。不管这个类创建了多少个对象,静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享。

静态成员属于类,而不是对象

静态变量,是在编译阶段就分配空间,对象还没有创建时,就已经分配好空间,

a/静态成员变量必须在类中声明,在类外定义。

类没有创建对象时,并没有开辟空间

静态变量可以通过类名称加作用域::来访问,或者对象来访问

普通成员变量,属于对象,只能通过对象名访问

注意;

1、静态成员函数的目的,操作静态成员数据

2、静态成员函数,不能访问非静态成员数据

3、普通成员函数可以操作静态成员数据和非静态成员数据

COnst静态成员属性

如果一个类的成员,既要实现共享,又要实现不可改变,那就用static const修饰。定义静态const数据成员时,最好在类内部初始化

单例模式设计是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统的资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

知识点十this指针

c++的封装性:将数据和方法封装在一起

数据和方法是分开存储

数据存储在每个对象中。

每个对象拥有独立的数据

每个对象共享

方法:是对象共有的

数据是对象独有

方法是对象共享

方法在代码区

当一个对象,调用setNum方法时,会在setNum方法中产生一个this指针,this指向所调用方法的对象

this指针的引用

Data ob1;

this=&ob1

void setNum(int num)

{

this-》m_num= num;

m_num = num;

}

任何非静态成员内部都有一个this指针

哪个对象调用方法,那么方法中的this就指向哪个对象

this指针是隐形存在的,不需要我们定义的。

c++的数据和操作也是分开存储,并且每一个非内联成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码,那么问题是:这一块代码是如何区分那个对象调用自己的呢

this指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针this,用以保存这个对象的地址,this指针也称为指向本对象的指针

this指针是C++实现封装的一种机制,它将对象和该对象调用的成员函数连接在一起,在外部看来,每一个对象都拥有自己的函数成员。一般情况下,并不写this,而是让系统进行默认配置,this指针永远指向当前对象。

成员函数可以通过this指针即可知道操作的是那个对象的数据。

注意:静态成员函数内部没有this指针,静态成员函数不能操作非静态成员变量。

静态成员函数属于类,函数内部没有this指针

10.1this指针的应用

在类的普通成员函数中,返回对象本身(*this)

10.2const修饰成员函数

用const修饰的成员函数时,const修饰this指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量,当成员变量类型符前用mutable修饰时例外

10.3const修饰对象叫常对象

常对象,只能调用const修饰的函数遍历成员

const int num=10;  //系统不不开辟空间,num被放入符号表中,如果后期对&num这时系统才会给num开辟空间

编译器认为 普通成员函数 存在修改成员变量 可能

10.4友元函数是一种特权函数

类的主要特点之一是数据隐藏,c++允许友元访问私有数据

友元语法

friend 关键字只出现在声明处、其他类、类成员函数、全局函数都可声明为友元。友元函数不是类成员,不带this指针,友元函数可访问对象任意成员属性,包括私有属性

10.4.1类的某个成员函数,作为另一个类的友元

10.4.2一个类整体作为另一个类的友元

知识点十一【运算符重载】

运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

运算符重载的目的:简化操作,让已有的运算符适应不同的数据类型

比如,我要重载“+”operator +重载=号运算符

知识点十三 继承的格式

派生类定义格式

Class 派生类 : 继承方式 基类名{

}

class 子类 :继承方式 父类{

}

继承方式

1、public公有继承(重要)公有派生

2、private私有继承、私有派生

protected 保护继承、保护派生

派生类继承基类,派生类拥有基类中全部成员变量和成员方法(除了构造和析构之外的成员方法),但是在派生类中,继承的成员并不一定能直接访问,不同的继承方法会导致不同的访问权限。

总结:

1、父类中的public数据,在子类中也是public、

父类中的private数据,在子类中是不可见的

父类中的protected数据,在子类中是protected的

(public 继承父类中的私有数据,在子类不可见,其他保持原样

2、class 子类:protected 父类

父类中的public数据,在子类中也是protected、

父类中的private数据,在子类中是不可见的

父类中的protected数据,在子类中是protected的

3、class 子类:privete 父类

父类中的public数据,在子类中也是private、

父类中的private数据,在子类中是不可见的

父类中的protected数据,在子类中是private的

a.继承中的构造和析构的顺序

先父类构造再子类构造,先子类析构,再父类析构

b.

知识点十四、

子类必须用,初始化列表,显示的调用父类的有参构造

//父类名称(参数)

//显示的调用父类的有参构造

//父类和子类的同名成员变量处理

1、当父类和子类成员变量同名时在子类就近原则选择本作用域的子类成员

2、如果在子类中,必须使用父类中的同名成员,必须加上父类的作用域。

3、子类可以借助父类的公有方法间接的操作父类的私有数据(不可见的数据)

为啥构造和析构除外?父类的构造和析构   只有父类自己知道该怎么做(构造和析构 系统自动调用)

子类会继承父类所有成员函数(构造和析构函数除外)和成员变量

知识点十四  静态成员属于类而不属于对象

知识点十五 虚继承

//继承的动作   虚继承

//父类    :虚基类

class 子类  :virtual  public  父类

{

};

vbptr(虚基类指针)其中v是virtual虚  b是base类   ptr指针

vbptr指向虚基类表

vbtable(虚基类

总结;之所以

知识点十六 多态

多态性:提供接口与具体实现之间的另一层隔离。

多态性改善了代码的可读性和组织性,同时也使创建的程序具有可延展性

静态多态和动态多态的区别就是函数地址早绑定(静态联编)还是晚绑定(动态联编)

静态多态(静态联编):函数入口地址是在编译阶段确定(运算符重载、函数重载)

动态多态(动态联编):函数入口地址是在运行阶段确定(虚函数)

用基类(指针或引用)保存子类对象(向上转换) 

1、基类指针、引用指向子类对象(安全)

Animal *p =new Cat

2、子类指针、引用指向基类对象(不安全)

(Cat *p = new Animal;

知识点十七 虚函数

虚函数本质是一个函数指针变量

如果Animal没有涉及到继承,函数指针变量就指向自身sleep

当虚函数涉及到继承的时候,子类会继承父类的(虚函数指针vfptr虚函数表vftable),编译器会将虚函数表中的函数入口地址更新成子类的同名(返回值、参数都相同)的函数入口地址

如果基类指针、引用访问虚函数的时候就会间接的调用子类的虚函数

你可能感兴趣的:(学习)