一、new的使用
格式1: 指针名 = new 类型;
格式1: 指针名 = new 类型(初始化值 );
格式1: 指针名 = new 类型[元素个数];
2.释放内存
格式1:delete 指针名
格式2: delete[] 指针名 只正对于new数组的情况
3.new malloc的区别(面试题)
第一点:new是c++的,malloc是c的。
第二点:new是运算符 ,malloc是函数,new要快于malloc
第三点:malloc申请失败返回NULL,new申请失败返回异常;
第四点: new和malloc都是在堆区申请的内存
第五点:new是创建对象,创建的对象不需要强转,malloc需要
第六点: new的申请需要delete释放,malloc的申请需要free
4. 注意: new 和delete是运算符 不是函数。
代码:
- #include
-
-
- using namespace std;
- struct student
- {
- int age;
- };
- int main()
- {
- char* pc = new char(0);
- int * pi = new int;
- double * pd = new double[10];
- struct student* ps = new struct student;
-
-
- delete pc;
- delete pi;
- delete[] pd;
- delete ps;
- }
二、类型转换
c语言类型转换 (类型)变量名
c++四种
第一种: const_cast 把const类型变量转换成非const类型变量
格 式:const_cast<类型> (变量名)
练 习: 定义const指针变量,转换成非const,然后修改值后打印出来
注意: 尖括号不可以省略 小括号不要省略
const_case 的尖括号中必须是指针或者引用类型
第二种:dynamic_cast
作用: 用于多态中类型的转换。(暂时不讲)
第三种:static_cast
作用:用于基本数据类型转换,也可以用于不同类对象的转换(父子类)
格式: static_cast<类型>(变量)
double 转换成int
特点:不会进行安全检查。
第四种:reinterpret_cast
作用: 属于底层的强制类型转换,进行二进制的数据拷贝。
使用: reinterpret_cast <类型>(变量名)
代码:
- #include <iostream>
-
- int main()
- {
-
- //第一种数据类型转化
- int z = 10;
- const int* y = &z ;
- int* x = const_cast<int*> (y);
- cout << (*x) <<endl;
- //第二种数据类型转化
- double db = 123.8456;
- int idb = static_cast<int>(db);
- idb++;
- cout << idb <<endl;
-
-
-
- }
三、面向对象
1.面向对象编程(oop)
主要是为了隔离数据,保护内部数据不被随意修改,同时限定变量的使用区域
2.类定义
定义一个类,有属性(成员变量),有行为(成员函数)。
格式: class 类名
{
修饰符:
定义变量;
定义函数;
};
3.c++中结构体和类的区别
第一个:在结构体中,默认为共有属性,而在类中是私有属性。
4.成员修饰符
共有属性: public: 可以在类内使用(类内函数中),可以在类外使用,可以在子类中使用。
私有属性: private 只可以用于当前类内使用,类外和子类没法使用
保护属性: protected:当前类内使用,子类使用。
5.定义对象:类名 对象名;
对象名.成员变量;
对象名.成员函数();
对象指针 = new 类名称; 使用成员变量是需要用->
对象指针->成员变量
对象指针->成员函数();
代码: 四、构造和析构 代码: 8.单列模式: 何为单列模式 ; 不管实例化你创建多少的对象,我只给你们返回的总是哪一个 为什么这样写呢?我们来解释几个关键点: 1.要想让一个类只能构建一个对象,自然不能让它随便去做new操作,因此Signleton的构造方法是私有的。 2.instance是Singleton类的静态成员,也是我们的单例对象。它的初始值可以写成Null,也可以写成new Singleton()。至于其中的区别后来会做解释。 3.getInstance是获取单例对象的方法。 如果单例初始值是null,还未构建,则构建单例对象并返回。这个写法属于单例模式当中的懒汉模式。 如果单例对象一开始就被new Singleton()主动构建,则不再需要判空操作,这种写法属于饿汉模式。 这两个名字很形象:饿汉主动找食物吃,懒汉躺在地上等着人喂。但是上边单列不是线程安全的单列!
6.声明和实现分离
原因:类什么和实现分离时为了隐藏实现部分。
实现接口化编程;
格式:
定义类: class student {public: void show(); };
类外实现: void student::show(){cout <
7.成员变量的set和get方法(私有)
get是获取成员变量的值
set是设置成员变量的值。
1构造函数:用来构造对象,每个对象创建时都会调用构造函数。
如果没有手动写构造,编译器会自动添加一个。
构造用来做初始化处理,变量的赋值,申请内存。
2格 式: 类名(参数){ 内容}
3注 意:构造函数的函数名是类名相同
构造函数没有返回值
构造函数有参合无参构成了重载
默认的构造函数,没有参数的函数版本 student(){ }
只要手动添加了构造,默认的构造就会消失。
只要手动添加的构造,都必须要有无参构造。(养成好习惯)
4构造调用:构造函数不需要主动调用,当定义对象时会自动调用
对于有参构造,在定义对象时需要加小括号和参数,例如 stduent danny(10);
对于无参构造,直接类名+对象名构建对象,不需要加括号 例如 student danny;
如果某一个对象当做函数的参数,为了防止内存拷贝,需要使用引用。
5.析构函数
作用:在对象释放时内核自动调用析构函数
用来释放内存空间,用来关闭句柄等善后操作
格式:~类名(){}
注意:析构函数的名称是在类名前加~
析构函数不可以主动调用
析构函数没有参数,不可以有参数。
如果没有手动添加析构,编译器会自动添加析构函数。
案例:
class student {
private: int age;
public: student(int a);
student();
~student(){};
void setAge(int a) { age = a; }
int getAge() { return age; }
};
6. 拷贝构造
拷贝构造:他是一种特殊的构造 (没有返回值,函数名是类名),特殊在参数是另外一个对象。
格式: 类名(类名& 对象名){xxxx}
调用: student dannyzai(danny);
student dannyzai = danny; 拷贝构造
fun(student abc){} //避免拷贝构造 加引用
7.拷贝方式:
浅拷贝:浅拷贝只是拷贝了指针指向,不申请内存空间,存在多次释放相同内存的危险,需要避免使用。
注意:如果没有手动写拷贝构造,编译器会自动添加默认的浅拷贝构造函数。
在拷贝构造函数中 要防止自拷贝 if(this != &other)
在拷贝构造中,如果指针不为空,需要先释放内存再进行申请
深拷贝:深拷贝拷贝的是另一个对象的内容,不拷贝地址,新的对象有自己单独的内存空间,不会进行double free的情况。