new和delete关键字
在C++中提供了new和delete关键字,new用来开辟内存,delete用来释放内存,并且new会自动调用构造函数,delete关键字会自动调用析构函数,与C语言中中malloc和free中不同的是,这个两个函数不会调用构造函数和析构函数。
当不用调用构造函数与析构函数的时候,它们的功能是一样的
//C语言语法
int *p = (int *)malloc(sizeof(int));
*p = 200;
//C++语法
int *p2 = new int;
*p2 = 200;
delete p2;
//C++语法中是分配一个内存,并且初始化
int *p3 = new int(200);
delete p3;
//C语言生成一个数组
int *pArray = (int *)malloc(sizeof(int) * 2);
p[0] = 1;
free(p);
//C++语法分配一个数组
int *pArray = new int[2];
pArray[0] = 2;
delete[] pArray;
//这种写法不会调用构造函数和析构函数
Test *pT1 = (Test *)malloc(sizeof(Test));
free(pT1);
//new能调用构造函数,delete能自动调用析构函数,作用都是开辟内存和释放内存
Test *pT2 = new Test(10);
delete pT2;
所以在C++中如果建议使用new和delete语法,因为在析构的时候,可能要附带析构其他对象,使用delete语法,能更安全。
静态成员属性与函数
如果你希望某个属性可以被所有该类对象共用,那么,你可以定义成静态成员属性,同样的,你还可以在其他类中引用到这个属性
class T{
public:
static int a;
}
//初始化的时候,一定要在外面初始化,防止重复开辟内存
int T::a = 100;
int main(){
cout<<T::a<<endl;
//当然你也可以直接通过某个对象调用到这个属性
T t;
cout<<t.a<<endl;
//你也可以在main函数再次修改T中a的值,这时候,你只需要通过T::a就能引用和修改其值,不过在此之前必须先在T外初始化
T::a = 200;
cout<<T::a<<endl;
return 0;
}
如上讲述如何将一个类的属性设置成静态,你同样可以将一个函数设置成静态成员函数
#include "iostream"
using namespace std;
class T {
public:
int c;
static int a;
static void test() {
cout << "hello" << endl;
}
};
int T::a = 1;
int main() {
T::a = 2;
cout << T::a << endl;
T::test();
system("pause");
return 0;
}
这里通过T::test();就能直接访问该函数,但是如果你在test()方法中使用非静态成员属性或者函数的时候,编译器就会报错,例如你在test函数中使用c变量,c变量是非静态的,那么既然它的非静态的,它属于某个对象,而如果你在静态函数中引用这个对象,编译器无法识别它属于哪个对象的,除非你通过某个对象引出这个属性,对于非静态成员函数在静态成员函数中使用,也是不允许的,道理和上面一样。
this指针
在C++中,非静态成员属性,静态成员属性,非静态成员函数和静态成员函数,编译器是如何管理它们的,事实上
成员属性–存储于对象中,于struct相同
静态成员变量–存储于全局区中
成员函数–存储于代码块中
静态成员函数–存储于全局区中
通过如上写法,你可能会想到一个问题,既然成员函数并没存储在当前对象,那么我们使用这个对象调用这个函数,并给当前当前对象的成员属性赋值的时候,编译器是如何知道当前是哪个对象,我应该使用这个函数给哪个成员属性赋值呢,事实上,编译器在处理这种情况的时候,会增加一个this指针,然后通过这个指针,指向要赋值对象,再给这个对象赋值,下面用C语言模拟编译器实现面向对象的封装
struct Test{
int i;
};
void Test_init(Test * this,int i){
this->i = i;
}
int Test_getI(Test * this){
return this->i;
}
void Test_Print(){
printf("This is class Test. \n");
}
Test a;
Test_init(&a,100);
Test_getI(&a);
Test_Print();
如果将以上代码转换成C++实现
class Test{
private:
int i;
public:
Test(int i){
this->i = i;
}
int getI(){
return this->i;
}
static void print(){
printf("This is class Test.\n");
}
};
Test a(100);
a.getI();
Test::print();
分配使用C++和C实现你会清楚的发现,事实上,只是C++编译器帮助我们省去了this指针这个参数。
将this指向的元素直接返回,那么这时候可以通过*this来获取到这个对象并返回
练习
//Array.h
#pragma once
class Array
{
private:
int length;
int * space;
public:
Array(int length);
Array(const Array & array);
int getLength();
void setData(int index, int value);
int getData(int index);
~Array();
};
//Array.cpp
#include "Array.h"
#include "iostream"
Array::Array(int length)
{
if (length < 0)length = 0;
//this->space = (int *)calloc(length, sizeof(int));
this->space = new int[length];
this->length = length;
}
Array::Array(const Array & array) {
//this->space = (int *)calloc(array.length, sizeof(int));
this->space = new int[array.length];
this->length = array.length;
for (int i = 0; i < array.length; i++) {
(this->space)[i] = array.space[i];
}
}
int Array::getLength() {
return this->length;
}
void Array::setData(int index, int value) {
(this->space)[index] = value;
}
int Array::getData(int index) {
return (this->space)[index];
}
Array::~Array()
{
//free(this->space);
if(this->space)
delete [] this->space;
}