目录
十、构造函数
1、构造函数定义
1.1、特点
-
以类名作为函数名
-
无返回值类型
1.2、作用
-
初始化对象的数据成员
-
类对象被创建时,编译器为对象分配内存空间并自动调用构造函数以完成成员的初始化
1.3、构造函数的种类
-
一般构造(重载构造)
-
无参构造
-
拷贝构造
注意:
-
如果创建的类中未书写任何构造函数,系统会自动生成默认的无参构造函数(函数为空,什么都不做)
-
如果书写了构造函数,系统就不会在自动生成默认构造函数;如果希望有一个这样的无参构造函数,需要自己书写出来
2、带参构造
2.1、定义
类名::构造(类型1 参数1,类型2 参数2,...)
{
//相关初始化代码
}
例如
Student::Student(string name, string desc)
{
_name = name; //外部name传入内部_name
_desc = desc;
}
Student *stu = new Student("撒贝宁","北大还行");
stu -> ShowInfo();
十一、栈内存与堆内存
堆内存:全局数据区(建议使用)
栈内存:速度快,临时变量,无法返回变量,使用完会立马被释放
十二、析构函数
定义:
-
对象过期时自动调用的特殊成员函数
-
析构函数一般用来完成清理工作
-
析构函数的名称是在类名前加上~(析构函数没有参数,只能有一个)
class studengt
{
private:
double* score;
public:
student(int len)
{
//使用new分配资源
score = new double[len];//new与delete相对应
}
~student() //析构函数
{
delete score; //释放资源
}
}
注意:
-
析构函数用来释放对象使用的资源,并销毁对象的非static数据成员
-
无论何时一个对象被销毁,都会自动调用其析构函数(隐式析构)
十三、使用类创建对象
1、第一种实例化方式:
栈内存中创建:类似声明变量
自定义类型名 对象名[([参数列表])]
student stu();
student stu;
注意:
-
stu对象系统创建并释放,不用担心会出现内存泄漏
-
声明周期只在声明区域的大括号内
-
栈内存的优势是存取速度比较快(仅次于寄存器),缺点是存在栈中数据大小与生存期必须是确定的,缺乏灵活性
2、第二种实例化方式:
在堆内存中创建:需要new关键字
student* p_stu1 = new student();
student* p_stu2 = new student;
auto* p_stu3 = new student();
auto:占用符(非真正类型),自动推断类型,根据new student()自动推断类型,适应C++11
注意:
-
p_stu1是指针,必须使用delete释放
-
使用灵活(可以赋值给全局变量,可以把对象作为函数的返回指返回)
-
用好功能强大,用不好危险
十四、this关键字
1、this指针
-
每个成员函数(包括构造和析构)都有一个this指针
-
this指针指针指向调用对象,即可以通过this关键字访问当前对象的成员
访问成员变量
this -> 成员名;
访问成员函数
this -> 函数名;
注意:
-
this指针的类型为类型*const(类名*const),为右值
-
this指针本身不占用大小,它并不是对象的一部分,因此不会影响sizeof的结果
-
this的作用域在类成员函数的内部
-
this指针是类成员函数的第一个默认隐含参数,编译器自动维护传递,类编写者不能显示传递
-
只有再类的非静态成员函数中才可以使用this指针,其他任何函数都不可以
十五、运算符重载
运算符重载就是“想法转换”,它的目标是简化调用的方式
-
把标准的函数使用函数,重新定义为自己认为的方式
-
所谓重载,就是赋予新的含义
-
运算符重载也是一个道理,同一个运算符可以有不同的功能
运算符的使用:
-
+号可以对不同类型(int、float等)得数据进行加法操作
-
<<既是位移运算符,又是配合cout向控制台输出数据
-
C++本身已经对这些运算符进行了重载
下面常见重载:
int num = num1 + num2;
cout << "hello world" << endl;
cin >> num ;
person *p = new person;
delete p;
person * pArray = new person[10];
delete[] pArray;
//Integer.h
#ifndef INTEGER_H
#define INTEGER_H
//自己定义的整形类,表示将整形封装成类,以便实现面向对象的封装
class Integer
{
public:
Integer();
Integer(int value):m_value(value){}
//c\重载+运算符
Integer operator+(Integer other);
int IntValue(){return m_value;}
virtual ~Integer();
protected:
private:
int m_value; //实际的整形数字(member)
};
#endif // INTEGER_H
//Integer.cpp
#include "Integer.h"
///默认构造时,会为私有m_value赋一个默认值0
Integer::Integer() : m_value(0)
{
//ctor
}
///c\重载+运算符
Integer Integer::operator+(Integer other) //可以将operator+看作特殊的函数名
{
Integer result(this->m_value + other.m_value); ///加法结果返回对象
return result;
}
Integer::~Integer()
{
//dtor
}
//main.cpp
#include <iostream>
#include "Integer.h"
using namespace std;
void TestInteger();
int main()
{
cout << "Hello world!" << endl;
TestInteger();
return 0;
}
void TestInteger()
{
Integer int1(1024),int2(2048),int3;
int3 = int1 + int2;
cout << "(int3 = int1 +int2)resuit is:" << int3.IntValue() << endl;
}
注意:
-
运算符重载的语法格式:
返回类型 operater被重载的运算符(参数列表)
-
编译器实际调用:
num3=num1.operator + (num2); //编译器内部操作
十六、详解const
1、const修饰指针变量时:
-
只有一个const时,如果const位于*的左侧,表示指针所指的数据常量,不能通过该指针修改实际数据
-
指针本身是变量,可以指向其他内存单元
-
只有一个const时,如果const位于*的右侧,表示指针本身是常量,不能指向其他内存单元,所指向的数据可以修改
int num1 = 1024;
const int * ptr1_num1 = &num1;
int const * ptr2_num1 = &num1; //指针所指的数据常量,不能通过该指针修改实际数据
int * const ptr3_num1 = &num1; //指针本身是常量,不能指向其他内存单元,所指向的数据可以修改
ptr3_num1 = ptr2_num1; //错误,不合法
-
如果由两个const位于*的左右两侧,表示指针和指针所指向的数据都不能修改
2、const修饰函数参数
-
传递来的参数在函数体内不可改变,与修饰变量时的性质一致
void constTest(const int num)
{
num = 123; //错误,不合法
}
-
const修饰引用时,不能修改引用对象的任何成员,好处是可以保护传递参数,不需要一个新的副本(copy)
-
使用const传递对象的引用时,可以起到不copy对象的目的(节省效率)
-
const成员函数不能调用非const成员函数
3、const修饰返回值
-
使用const修饰引用类型的一个常见原因是提高效率