一、类和对象、this指针
1、谈谈对面向对象(OO,Object Oriented)的理解
类(属性和行为) =》 实体的抽象类型(ADT) 面向对象的思维是,当我碰到这个问题域的时候,碰到这个程序的时候,我首先应该把这个问题里有哪些对象,对象与对象之间有什么关系抽象出来。对象通过“属性(attribute)”和“方法(method)”来分别对应事物所具有的静态属性和动态属性。类是用于描述同一类的对象的一个抽象的概念,类中定义了这一类对象所具有的静态属性和动态属性。类可以看成一类对象的模板,对象可以看成该类的一个具体实例。OOP有四大特征:抽象、封装、继承和多态。封装就是访问限定符:public公有的、private私有的、protected保护的。
#include <iostream>
using namespace std;
const int NAME_LEN = 20;
class CGoods
{
public:
void init(const char* name, double price, int amount);
void show();
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];
double _price;
int _amount;
};
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 << "price:" << _price << endl;
cout << "amount" << _amount << endl;
}
int main()
{
CGoods good1;
good1.init("面包", 10.0, 200);
good1.show();
good1.setPrice(20.5);
good1.setAmount(100);
good1.show();
CGoods good2;
good2.init("空调", 10000.0, 50);
good2.show();
return 0;
}
运行结果 对象占用内存的大小,只和成员变量有关(不考虑static成员变量),与成员方法无关
查看对象占用内存大小:打开vs工具->visual studio命令提示,cd test.cpp所在目录,输入 cl test.cpp /d1reportSingleClassLayoutCGoods this指针的作用:
一个类产生了很多对象,每一个对象都有自己的成员变量,但是同一个类型的对象共享一套成员方法。那么一套成员方法如何区分不同的对象呢?就是通过this指针来区分的,成员方法一经编译,方法的参数都会添加一个this指针,用来接收调用该方法的对象。所以在成员方法里访问的其他成员变量或调用其他的成员方法前面都会默认加this指向。
二、掌握构造函数和析构函数
构造函数:定义对象时,自动调用的;可以重载的;构造完后,对象产生了
析构函数:不带参数,不能重载,只有一个析构函数;析构完成后,对象就不存在,但内存还在。
#include <iostream>
using namespace std;
class SeqStack
{
public:
SeqStack(int size = 10)
{
cout << this << "SeqStack()" << endl;
_pstack = new int[size];
_top = -1;
_size = size;
}
~SeqStack()
{
cout << this << "~SeqStack()" << endl;
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];
}
delete[]_pstack;
_pstack = ptmp;
_size *= 2;
}
};
SeqStack gs;
int main()
{
SeqStack* ps = new SeqStack(60);
ps->push(70);
ps->push(80);
ps->pop();
cout << ps->top() << endl;
delete ps;
SeqStack s;
for (int i = 0; i < 15; i++)
{
s.push(rand() % 100);
}
while (!s.empty())
{
cout << s.top() << " ";
s.pop();
}
cout << endl;
SeqStack s1(50);
return 0;
}
三、对象的深拷贝和浅拷贝
拷贝构造:是在用已存在的对象构造新生成的对象的时候自动调用;
赋值函数:用已存在的对象给已存在的对象进行赋值的过程自动调用的函数。
对象默认的拷贝构造和赋值函数都是做内存的数据拷贝,也就是浅拷贝。关键是对象如果占用外部资源,那么浅拷贝就出现问题了!析构时会对同一资源进行多次释放,后析构的就会出错!
举例代码:
(1)栈
#include <iostream>
using namespace std;
class SeqStack
{
public:
SeqStack(int size = 10)
{
cout << this << "SeqStack()" << endl;
_pstack = new int[size];
_top = -1;
_size = size;
}
SeqStack(const SeqStack& src)
{
cout << "SeqStack(const SeqStack& src)" << endl;
_pstack = new int[src._size];
for (int i = 0; i <= src._top; i++)
{
_pstack[i] = src._pstack[i];
}
_top = src._top;
_size = src._size;
}
void operator=(const SeqStack& src)
{
cout << "operator=(const SeqStack& src)" << endl;
if (&src == this)
{
return;
}
delete[]_pstack;
_pstack = new int[src._size];
for (int i = 0; i <= src._top; i++)
{
_pstack[i] = src._pstack[i];
}
_top = src._top;
_size = src._size;
}
~SeqStack()
{
cout << this << "~SeqStack()" << endl;
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];
}
delete[]_pstack;
_pstack = ptmp;
_size *= 2;
}
};
int main()
{
SeqStack s;
SeqStack s1(10);
SeqStack s2 = s1;
s2 = s1;
return 0;
}
运行结果: (2)string类
#include <iostream>
using namespace std;
class String
{
public:
String(const char* str = nullptr)
{
if (str != nullptr)
{
m_data = new char[strlen(str) + 1];
strcpy(m_data, str);
}
else
{
m_data = new char[1];
*m_data = '\0';
}
}
String(const String& src)
{
m_data = new char[strlen(src.m_data) + 1];
strcpy(m_data, src.m_data);
}
~String()
{
delete[]m_data;
m_data = nullptr;
}
String& operator=(const String& src)
{
if (&src == this)
{
return *this;
}
delete[]m_data;
m_data = new char[strlen(src.m_data) + 1];
strcpy(m_data, src.m_data);
return *this;
}
private:
char* m_data;
};
int main()
{
String str1;
String str2("hello");
String str3 = "world";
String str4 = str3;
String str5(str3);
str1 = str2;
return 0;
}
(3)循环队列
#include <iostream>
using namespace std;
class Queue
{
public:
Queue(int size = 10)
{
_pQue = new int[size];
_front = _rear = 0;
_size = size;
}
Queue(const Queue& src)
{
_front = src._front;
_rear = src._rear;
_size = src._size;
_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 (&src == this)
{
return *this;
}
delete[]_pQue;
_front = src._front;
_rear = src._rear;
_size = src._size;
_pQue = new int[_size];
for (int i = _front; i != _rear; i = (i + 1) % _size)
{
_pQue[i] = src._pQue[i];
}
return *this;
}
~Queue()
{
delete[]_pQue;
_pQue = nullptr;
}
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 _front == _rear; }
private:
int* _pQue;
int _front;
int _rear;
int _size;
void resize()
{
int* ptmp = new int[2 * _size];
int index = 0;
for (int i = _front; i != _rear; i = (i + 1) % _size)
{
ptmp[index] = _pQue[i];
index++;
}
delete[]_pQue;
_pQue = ptmp;
_front = 0;
_rear = index;
_size *= 2;
}
};
int main()
{
Queue queue;
for (int i = 0; i < 20; i++)
{
queue.push(rand() % 100);
}
while (!queue.empty())
{
cout << queue.front() << endl;
queue.pop();
}
cout << endl;
Queue queue1 = queue;
return 0;
}
四、构造函数的初始化列表
#include <iostream>
using namespace std;
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, int a, int p, int y, int m, int d)
:_date(y,m,d)
,_amount(a)
,_price(p)
{
strcpy(_name, n);
}
void show()
{
cout << "name:" << _name << endl;
cout << "amount:" << _amount << endl;
cout << "price:" << _price << endl;
_date.show();
}
private:
char _name[20];
int _amount;
double _price;
CDate _date;
};
int main()
{
CGoods good("商品1", 100, 35.0, 2019, 5, 21);
good.show();
return 0;
}
成员变量的初始化和它们定义的顺序有关,和构造函数初始化列表中出现的先后顺序无关!
举例:
#include <iostream>
using namespace std;
class Test
{
public:
Test(int data = 10) :mb(data), ma(mb) {}
void show() { cout << "ma:" << ma << endl << "mb:" << mb << endl; }
private:
int ma;
int mb;
};
int main()
{
Test t;
t.show();
return 0;
}
运行结果:
五、类的各种成员方法及区别
类的各种成员方法 - 成员方法/变量
1.普通的成员方法=>编译器会添加一个this形参变量
(1)属于类的作用域
(2)调用该方法时,需要依赖一个对象
(3)可以任意访问对象的私有成员
2.static静态成员方法=>不会生成this形参
(1)属于类的作用域
(2)用类名作用域来调用方法
(3)可以任意访问对象的私有成员,仅限于不依赖对象的成员(只能调用其他的static静态成员)
3.const常成员方法=>const CGoods *this
(1)属于类的作用域
(2)调用依赖于一个对象,普通对象或者常对象都可以
(3)可以任意访问对象的私有成员,但是只能读,而不能写
#include <iostream>
using namespace std;
#if 1
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, int a, int p, int y, int m, int d)
:_date(y,m,d)
,_amount(a)
,_price(p)
{
strcpy(_name, n);
_count++;
}
void show()
{
cout << "name:" << _name << endl;
cout << "amount:" << _amount << endl;
cout << "price:" << _price << endl;
_date.show();
}
void show()const
{
cout << "name:" << _name << endl;
cout << "amount:" << _amount << endl;
cout << "price:" << _price << endl;
_date.show();
}
static void showCGoodsCount()
{
cout << "所有商品的种类数量是:" << _count << endl;
}
private:
char _name[20];
int _amount;
double _price;
CDate _date;
static int _count;
};
int CGoods::_count = 0;
int main()
{
CGoods good1("商品1", 100, 35.0, 2019, 5, 21);
good1.show();
CGoods good2("商品2", 100, 35.0, 2019, 5, 21);
good2.show();
CGoods good3("商品3", 100, 35.0, 2019, 5, 21);
good3.show();
CGoods good4("商品4", 100, 35.0, 2019, 5, 21);
good4.show();
CGoods::showCGoodsCount();
const CGoods good5("非卖品商品5",100,35.0,2019,5,21);
good5.show();
return 0;
}
#endif
运行结果:
六、指向类成员的指针
#include <iostream>
using namespace std;
class Test
{
public:
void func() { cout << "call Test::func" << endl; }
static void static_func() { cout << "Test::static_func" << endl; }
int ma;
static int mb;
};
int Test::mb;
int main()
{
Test t1;
Test* t2 = new Test();
void (Test:: * pfunc)() = &Test::func;
(t1.*pfunc)();
(t2->*pfunc)();
void (*static_func)() = &Test::static_func;
Test::static_func();
int Test::* p = &Test::ma;
t1.*p = 20;
cout << t1.*p << endl;
t2->*p = 30;
cout << t2->*p << endl;
int* p1 = &Test::mb;
*p1 = 40;
cout << *p1 << endl;
delete t2;
return 0;
}
|