C++复习0.1——三目const重载类和对象

xiaoxiao2021-02-28  75

C++复习0.1


三目运算符

c语言三目运算表达式返回值为数据值,为右值,不能赋值

int a = 10; int b = 20; printf("ret:%d\n", a > b ? a : b); //思考一个问题,(a > b ? a : b) 三目运算表达式返回的是什么? //(a > b ? a : b) = 100; //返回的是右值

c++语言三目运算表达式返回值为变量本身(引用),为左值,可以赋值

int a = 10; int b = 20; printf("ret:%d\n", a > b ? a : b); //思考一个问题,(a > b ? a : b) 三目运算表达式返回的是什么? cout << "b:" << b << endl; //返回的是左值,变量的引用 (a > b ? a : b) = 100;//返回的是左值,变量的引用 cout << "b:" << b << endl;

const

在c++中,一个const不必创建内存空间,而在c中,一个const总是需要一块内存空间。在c++中,是否为const常量分配内存空间依赖于如何使用。一般说来,如果一个const仅仅用来把一个名字用一个值代替(就像使用#define一样),那么该存储局空间就不必创建。 如果存储空间没有分配内存的话,在进行完数据类型检查后,为了代码更加有效,值也许会折叠到代码中。 不过,取一个const地址, 或者把它定义为extern,则会为该const创建内存空间。 在c++中,出现在所有函数之外的const作用于整个文件(也就是说它在该文件外不可见),默认为内部连接,c++中其他的标识符一般默认为外部连接。

**C/C++中const异同

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

const int constA = 10; int main(){ int* p = (int*)&constA; *p = 200; }

代码以上在c/c++中编译通过,在运行期,修改constA的值时,发生写入错误。原因是修改只读数据段的数据

c语言中局部const存储在堆栈区,只是不能通过变量直接修改const只读变量的值,但是可以跳过编译器的检查,通过指针间接修改const值 c++中对于局部的const变量要区别对待:

对于基础数据类型,也就是const int a = 10这种,编译器会把它放到符号表中,不分配内存,当对其取地址时,会分配内存对于基础数据类型,如果用一个变量初始化const变量,如果const int a = b,那么也是会给a分配内存对于自定数据类型,比如类对象,那么也会分配内存

c中const默认为外部连接,c++中const默认为内部连接.当c语言两个文件中都有const int a的时候,编译器会报重定义的错误。而在c++中,则不会,因为c++中的const默认是内部连接的。如果想让c++中的const具有外部连接,必须显示声明为: extern const int a = 10

const由c++采用,并加进标准c中,尽管他们很不一样。在c中,编译器对待const如同对待变量一样,只不过带有一个特殊的标记,意思是”你不能改变我”。在c中定义const时,编译器为它创建空间,所以如果在两个不同文件定义多个同名的const,链接器将发生链接错误。简而言之,const在c++中用的更好


函数重载实现原理

编译器为了实现函数重载,也是默认为我们做了一些幕后的工作,编译器用不同的参数类型来修饰不同的函数名,比如void func(); 编译器可能会将函数名修饰成_func,当编译器碰到void func(int x),编译器可能将函数名修饰为func_int,当编译器碰到void func(int x,char c),编译器可能会将函数名修饰为_func_int_char我这里使用”可能”这个字眼是因为编译器如何修饰重载的函数名称并没有一个统一的标准,所以不同的编译器可能会产生不同的内部名。


类和对象

**C和C++中struct的区别

c语言struct只有变量c++语言struct既有变量也有函数

**构造函数和析构函数

构造函数主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。 析构函数主要用于对象销毁前系统自动调用,执行一些清理工作。

构造函数语法:

 构造函数函数名和类名相同,没有返回值,不能有void,但可以有参数。  ClassName(){}

析构函数语法

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

拷贝构造函数的调用时机

对象以值传递的方式传给函数参数函数局部对象以值传递的方式从函数返回(看编译器的,有的有进行优化比如qt)用一个对象初始化另一个对象

深拷贝和浅拷贝

浅拷贝

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

深拷贝

当类中有指针,并且此指针有动态分配空间,析构函数做了释放处理,往往需要自定义拷贝构造函数,自行给指针动态分配空间,深拷贝

类对象作为成员

在类中定义的数据成员一般都是基本的数据类型。但是类中的成员也可以是对象,叫做对象成员。 C++中对对象的初始化是非常重要的操作,当创建一个对象的时候,c++编译器必须确保调用了所有子对象的构造函数。如果所有的子对象有默认构造函数,编译器可以自动调用他们。但是如果子对象没有默认的构造函数,或者想指定调用某个构造函数怎么办? 那么是否可以在类的构造函数直接调用子类的属性完成初始化呢?但是如果子类的成员属性是私有的,我们是没有办法访问并完成初始化的。 解决办法非常简单:对于子类调用构造函数,c++为此提供了专门的语法,即构造函数初始化列表。 当调用构造函数时,首先按各对象成员在类定义中的顺序(和参数列表的顺序无关)依次调用它们的构造函数,对这些对象初始化,最后再调用本身的函数体。也就是说,先调用对象成员的构造函数,再调用本身的构造函数。 析构函数和构造函数调用顺序相反,先构造,后析构。

explicit

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

explicit用于修饰构造函数,防止隐式转化是针对单参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造)而言

静态成员

在类定义中,它的成员(包括成员变量和成员函数),这些成员可以用关键字static声明为静态的,称为静态成员。 不管这个类创建了多少个对象,静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享。

静态成员变量

在一个类中,若将一个成员变量声明为static,这种成员称为静态成员变量。与一般的数据成员不同,无论建立了多少个对象,都只有一个静态数据的拷贝。静态成员变量,属于某个类,所有对象共享。 静态变量,是在编译阶段就分配空间,对象还没有创建时,就已经分配空间。

静态成员变量必须在类中声明,在类外定义静态数据成员不属于某个对象,在为对象分配空间中不包括静态成员所占空间静态数据成员可以通过类名或者对象名来引用

静态成员函数

在类定义中,前面有static说明的成员函数称为静态成员函数。静态成员函数使用方式和静态变量一样,同样在对象没有创建前,即可通过类名调用。静态成员函数主要为了访问静态变量,但是,不能访问普通成员变量。 静态成员函数的意义,不在于信息共享,数据沟通,而在于管理静态数据成员,完成对静态数据成员的封装。

静态成员函数只能访问静态变量,不能访问普通成员变量静态成员函数的使用和静态成员变量一样静态成员函数也有访问权限普通成员函数可访问静态成员变量、也可以访问非静态成员变量

const静态成员属性

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

const修饰成员函数

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

**成员变量和函数的存储

c++中的非静态数据成员直接内含在类对象中,就像c struct一样成员函数(member function)虽然内含在class声明之内,却不出现在对象中每一个非内联成员函数(non-inline member function)只会诞生一份函数实例

单例

Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其默认构造函数和拷贝构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

class Printer{ public: static Printer* getInstance(){ return pPrinter;} void PrintText(string text){ cout << "打印内容:" << text << endl; cout << "已打印次数:" << mTimes << endl; cout << "--------------" << endl; mTimes++; } private: Printer(){ mTimes = 0; } Printer(const Printer&){} private: static Printer* pPrinter; int mTimes; }; Printer* Printer::pPrinter = new Printer; void test(){ Printer* printer = Printer::getInstance(); printer->PrintText("离职报告!"); printer->PrintText("入职合同!"); printer->PrintText("提交代码!"); }
转载请注明原文地址: https://www.6miu.com/read-55826.html

最新回复(0)