C++ OOP面对对象 this指针
C:各种各样的函数定义 struct
C++:类==》实体的抽象类型
实体(属性,行为)-》ADT(abstract data type)
OOP语言的四大特征是什么?
抽象 封装/隐藏 继承 多态
访问限定符:public公有的 private私有的 protected保护的
#include<iostream>
#include<string>
using namespace std;
#if 0
const int NAME_LEN = 20;
class CGoods
{
public: //给外部提供公有的成员方法,来访问私有的属性
//做数据初始化
void init(const char*name, double price, int amount);
//打印信息
void show();
//给成员变量提供一个getXXX或setXXX的方法,类体内实现的方法,自动初始化inline
void setName(char *name){ strcpy(_name, name); }
void setPrice(double price){ _price = price; }
void setAmount(int amount){ _amount = amount; }
const char *getName(){ return _name; }
double getPrice(){ return _price; }
int getAmount(){ return _amount; }
private: //属性默认私有的成员变量
//对象内存大小的时候,对象的内存大小和成员变量有关
char _name[NAME_LEN];//20-》24
double _price;//8
int _amount;//4-》8
//24+8+8=40字节
};
void CGoods::init(const char*name, double price, int amount)
{
strcpy(_name, name);
_price = price;
_amount = amount;
}
void CGoods::show()
{
cout << "name:" << _name << endl;
cout << "prrice:" << _price << endl;
cout << "amount" << _amount << endl;
}
int main()
{
/*
CGoods可以定义无数的对象,每一个对象都有自己的成员变量,但是它们共享一套成员方法
show()==>怎么知道处理哪个对象的信息?
inti(name,price,amount)==> 怎么知道把信息初始化给哪一个对象?
类的成员方法一经编译,所有的方法参数,都会加一个this指针,接受调用该方法的对象的地址
void setName(this->char *name){};
*/
CGoods good1;//类实例化了一个对象
//good._price;//err
//init(&good1,"面包", 10.1, 20);
good1.init("面包", 10.1, 20);
good1.show();
//show(&good1);
good1.setAmount(200);
good1.show();
CGoods good2;
good2.init("冰箱",1980,20);
good2.show();
//new 的四种用法
int *p1 = new int(10);
int *p2 = new (nothrow)(int);
const int * p3 = new const int (2);
//定位new
int statu = 0;
int *p4 = new (&statu)int(30);
cout << "p4:" << *p4 << endl;
//c和c++的开辟动态内存:new | malloc
int *a = (int*)malloc( sizeof (int));
if (a == nullptr)
{
return -1;
}
free(a);
int *a1 = (int*)malloc(sizeof(int)* 20);
free(a1);
int *b = new int(20);
delete (b);
int *b1 = new int[20]();
delete[]b1;
//&&专门用来引用右值类型,指令上,可以自动产生临时量
int &&d = 20;//== const int &d = 20;
//int &d1 = 10;//--err
//不能用一个右值引用变量,来引用左值
int &c = d; //右值引用变量本身是一个左值,只能有左值引用它
c = 50;
cout << "c=" << d << endl;
return 0;
}
/*
构造函数和析构函数
OOP实现一个顺序栈
*/
class SeqStack
{
public:
//构造函数 SeqStack s1; SeqStack s2(20)
SeqStack(int size = 10) //是可以带参数的,因此可以提供多个构造函数
{
cout << this << "SeqStack()"<<endl;
_pstack = new int[size];
_top = -1;
_size = size;
}
//自定义构造函数 <=对象的浅拷贝有问题
SeqStack(const SeqStack &src)
{
cout << "SeqStack &src" << endl;
_pstack = new int[src._size];
for (int i = 0; i < src._size; i++)
{
_pstack[i] = src._pstack[i];
}
_top = src._top;
_size = src._size;
}
//析构函数
~SeqStack() //是不带参数的,所以析构函数只能有一个
{
cout << this << "~SeqStack()"<<endl;
delete[]_pstack;
_pstack = nullptr;
}
//赋值重载函数 s1 = s1
void operator=(const SeqStack &src)
{
cout << "operator=" << endl;
//防止自赋值
if (this == &src)return;
//需要先释放当前对象占用的资源;
delete[]_pstack;
_pstack = new int[src._size];
for (int i = 0; i < src._size; i++)
{
_pstack[i] = src._pstack[i];
}
_top = src._top;
_size = src._size;
}
/*void init(int size = 10)
{
_pstack = new int[size];
_top = -1;
_size = size;
}
void release()
{
delete[]_pstack;
_pstack = nullptr;
}*/
void push(int val)
{
if (full())
resize();
_pstack[++_top] = val;
}
void pop()
{
if (empty())
return;
--_top;
}
int top()
{
return _pstack[_top];
}
bool empty(){ return _top == -1; }
bool full(){ return _top==_size - 1; }
private:
int *_pstack;//动态开辟数组,存储顺序栈的元素
int _top;//指向栈顶元素的位置
int _size;//数组扩容的总大小
void resize()
{
int *ptmp = new int[_size * 2];
for (int i = 0; i < _size; i++)
{
ptmp[i] = _pstack[i];
//如果拷贝的是对象,对象指向了外部内存,那就出问题了(浅拷贝)
//memcopy(ptmp,_psatck,sizeof(int)*_size);
}
delete[]_pstack;
_pstack = ptmp;
_size *= 2;
}
};
SeqStack gb;//全局构造在程序运行结束析构
int main01()
{
//当我在堆区开辟内存,默认的析构函数不起作用,就需要自己delete
SeqStack *ps = new SeqStack(30);
ps->push(70);
ps->push(40);
cout<<ps->top()<<endl;
delete ps;//先调用ps->~SeqStack()+然后free(ps)
//1.开辟内存 2.调用构造函数
SeqStack s;
//s.init(5);//对象变量初始化操作
for (int i = 0; i < 15; i++)
{
s.push(rand() % 100);
}
while (!s.empty())
{
cout << s.top() << " ";
s.pop();
}
//s.release();//释放对象成员变量占用的外部堆内存(外部资源)
SeqStack s2(20);//先进后出(构造析构)
//s2.~SeqStack();//析构函数调用结束后,我们说对象不存在了
//s2.push(30);//堆内存的非法访问,析构之后不可在访问对象的成员
return 0;
}
/*
this指针 =》类-》很多对象 共享一套成员方法
成员方法,方法的参数都会添加一个this指针
构造函数:
定义对象时,自动调用的;可以重载的;构造完成,对象产生了
析构函数:
不带参数,不能重载,只有一个析构函数;析构完成,对象就不存在了
16.深拷贝和浅拷贝
对象默认的拷贝构造是做内存的数据拷贝
关键是对象如果占用外部的内存,那么浅拷贝就出现问题了!
*/
int main()
{
SeqStack s;//没有提供任何构造函数的时候,会为你生成默认构造函数和默认析构函数
SeqStack s1(10);
SeqStack s2 = s1;//#1 默认拷贝构造函数,做直接内存数据拷贝
//SeqStack s3(s1);//#2
//s2.operator=(s1);
s1 = s1;
return 0;
}
#endif
#if 0
/*
17.拷贝构造函数和赋值重载函数应用代码实践
*/
class String
{
public:
String(const char *str = nullptr)//普通构造函数
{
if (str != nullptr)
{
m_data = new char[strlen(str) + 1];
strcpy(this->m_data, str);
}
else
{
//置为空,让下面的拷贝构造函数不用重新判断是不是有效字符
m_data = new char[1];
m_data = '\0';
}
}
String(const String &other)//拷贝构造函数
{
m_data = new char[strlen(other.m_data)+1];
strcpy(m_data, other.m_data);
}
~String()
{
delete[]m_data;
m_data = nullptr;
}
//String& 是为了连续的operator的操作 s1=s2=s3
String& operator = (const String &other)//赋值重载函数
{
if (this == &other)
{
return *this;
}
m_data = new char[strlen(other.m_data)+1];
strcpy(m_data, other.m_data);
return *this;
}
private:
char *m_data;//用于保存字符
};
int main()
{
String str1;
String str2("hello");
String str3 = "world";
String str4 = str3;
String str5(str3);
str3 = str4;
return 0;
}
#endif
#if 0
//循环队列
class Queue
{
public:
Queue(int size = 5)
{
_pQue = new int[size];
_front = _rear = 0;
_size = size;
}
//可以限制用户使用拷贝和赋值构造函数
//Queue(const Queue&) = delete;
//Queue operator=(const Queue&) = delete;
Queue(const Queue &src)
{
_size = src._size;
_front = src._front;
_rear = src._rear;
_pQue = new int[_size];
for (int i = _front; i != _rear; i = (i + 1) % _size)
{
_pQue[i] = src._pQue[i];
}
}
Queue& operator=(const Queue &src)
{
if (this == &src)return *this;
delete[]_pQue;
_size = src._size;
_front = src._front;
_rear = src._rear;
_pQue = new int[_size];
for (int i = _front; i != _rear; i = (i + 1) % _size)
{
_pQue[i] = src._pQue[i];
}
return *this;
}
void push(int val)//入队操作
{
if (full())
resize();
_pQue[_rear] = val;
_rear = (_rear + 1) % _size;
}
void pop()//出队操作
{
if (empty())return;
_front = (_front + 1) % _size;
}
int front()//获取队头元素
{
return _pQue[_front];
}
bool full(){ return (_rear + 1) % _size == _front;}
bool empty(){ return _rear == _front; }
~Queue()
{
delete[]_pQue;
_pQue = nullptr;
}
private:
int *_pQue;//申请数组的空间
int _front;//队头
int _rear;//队尾
int _size;//扩容的大小
void resize()
{
int *ptmp = new int[_size * 2];
int index = 0;
for (int i = _front; i != _rear; i = (i + 1) % _size)
{
ptmp[index++] = _pQue[i];
}
delete[]_pQue;
_pQue = ptmp;
_front = 0;
_rear = index;
_size *= 2;
}
};
int main()
{
Queue q1;
for (int i = 0; i < 20; i++)
{
q1.push(rand() % 100);
}
while (!q1.empty())
{
cout << q1.front() << endl;
q1.pop();
}
Queue q2 = q1;
q1 = q2;
return 0;
}
#endif
#if 0
/*
18.构造函数初始化列表 : 可以指定当前对象成员变量的初始化方式
CDate信息 是 CGoods商品信息的一部分 a part of ... 组合关系(继承)
*/
class CDate
{
public:
CDate(int y, int m ,int d)//自定义了一个构造函数,编译器就不会默认生成构造函数
{
_year = y;
_month = m;
_day = d;
}
void show()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
class CGoods
{
public:
CGoods(const char * n, double p, int a,int y,int m, int d)
:_date(y,m,d)
,_amount(a)
,_price(p)// #1 构造函数的初始化列表
{
// #2 当前类类型构造函数体
strcpy(_name, n);
//_price = p;
//_amount = a;
}
void show()
{
cout << "name:" << _name << endl;
cout << "price:" << _price << endl;
cout << "amount:" << _amount << endl;
_date.show();
}
private:
char _name[20];
double _price;
int _amount;
CDate _date;//成员对象
};
int main()
{
CGoods g1("苹果",9.8,3,2019,3,8);
g1.show();
return 0;
}
class Test
{
public:
Test(int data = 10) :mb(data), ma(mb){}
void show()
{
cout << "ma:" << ma << "mb:" << mb << endl;
}
private:
//成员变量的初始化和它们定义的顺序有关,和构造函数列表中出现的先后顺序无关;
int ma;
int mb;
};
int main()
{
Test t1;
t1.show();
//ma:-858993460mb:10
return 0;
}
/*
19.掌握成员方法和区别
普通的成员方法 =》编译器会添加一个this形参变量
1.属于类的作用域
2.调用该方法时,需要依赖一个对象(常对象是无法调用的)
3.可以任意访问对象的私有成员变量 public,private
static静态成员方法 =》不会生成this形惨
1.属于类的作用域
2.用类名作用域来调用方法
3.可以任意访问对象的私有成员,仅限于依赖对象的成员(只能调用其他static静态成员)
const常成员方法 =》const CGoods *this
1.属于类的作用域
2.调用依赖一个对象,普通对象或者常对象都可以
3.可以任意访问对象的私有成员,但是只能读,不可写
*/
class CDate{
public:
CDate(int y, int m, int d)//自定义了一个构造函数,编译器就不会默认生成构造函数
{
_year = y;
_month = m;
_day = d;
}
void show()const
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
class CGoods
{
public:
CGoods(const char * n, double p, int a, int y, int m, int d)
:_date(y, m, d)
, _amount(a)
, _price(p)// #1 构造函数的初始化列表
{
// #2 当前类类型构造函数体
strcpy(_name, n);
_count++;//记录产生新对象的数量
}
//普通成员方法
void show()//打印商品的私有信息 CGoods *this
{
cout << "name:" << _name << endl;
cout << "price:" << _price << endl;
cout << "amount:" << _amount << endl;
_date.show();
}
//常成员方法:只要是只读操作的成员方法,一律实现成const常成员方法
void show()const//const CGoods *this
{
cout << "name:" << _name << endl;
cout << "price:" << _price << endl;
cout << "amount:" << _amount << endl;
_date.show();
}
//静态成员方法 没有this指针的
static void showCount()//打印的是所有商品共享的信息
{
cout << "所有商品种类数量是:" <<_count << endl;
//cout<<"name:"<<this->_name<<endl;//err
}
private:
char _name[20];
double _price;
int _amount;
CDate _date;//成员对象 1.分配内存 2.调用构造函数
//int _count;//用来记录商品对象的总数量
static int _count;//不属于对象,而是属于类级别的 声明
};
//static 成员变量一定要在类外进行定义并初始化
int CGoods::_count = 0;
int main()
{
CGoods g1("苹果1", 9.8, 3, 2019, 3, 8);
g1.show();
CGoods g2("苹果2", 9.8, 3, 2019, 3, 8);
g2.show();
CGoods g3("苹果3", 9.8, 3, 2019, 3, 8);
g3.show();
CGoods g4("苹果4", 9.8, 3, 2019, 3, 8);
g4.show();
//g2.showCount();//4
CGoods::showCount();
const CGoods g5("非卖品", 6.9, 4, 2022, 4, 6);
g5.show();
return 0;
}
#endif
/*
20.指向类成员(成员变量和成员方法)的指针
*/
class Test
{
public:
void func(){ cout << "call Test::func" << endl;}
static void static_func(){ cout << "Test::static_func" << endl; }
int ma;
static int mb;
private:
};
int Test::mb = 0;
int main()
{
/*无法从“int”转换为“int Test::*
int Test::*p = &Test::ma;
*p = 20;*/
Test t1;
Test *t2 = new Test();
#if 0
int Test::*p = &Test::ma;
t1.*p = 20;
cout << t1.*p << endl;//20
t2->*p = 30;
cout << t2->*p << endl;//30
int *p1 = &Test::mb;
*p1 = 40;
cout << *p1 << endl;//40
#endif
//指向成员方法的指针
/*无法从“void(__thiscall Test::*)(void)”转换为“void(__cdecl *)(void)
void(*pfunc)() = &Test::func;
(*pfunc)();*/
void(Test::*pfunc)() = &Test::func;
(t1.*pfunc)();
(t2->*pfunc)();
//如何定义函数指针指向类的static成员方法呢?
return 0;
}