目录
1.类和对象
在函数外部使用class建立一个类,这是一个虚拟的不部分,当要使用这个类的时候,就在主函数中,用class定义一个新的对象,这个对象包括类中的数据以及函数。
还要注意函数重载中,int add (int a,int b)------int add (int &a,in
int (*p)(int,int)----int (*p)(int &,int &)
#include <iostream>
#include <string>
using namespace std;
/*
类和对象
类:某一功能的数据以及算法的结合
c语言中的数据和算法是相互独立的,关联性不强
c++中的相关的数据以及结构进行封装形成结构体以及类,在没有使用到真的数据的时候,
结构体以及类都是一种虚拟的,当赋值了数据,数据才会有效,
这个数据我们就称为是对象,c++中的都是由各种类组成的,这就是面对对象
对类中的内容进行访问,要有访问修饰符
访问修饰符(3个):约束类成员的适用范围,默认的修饰方式是private
private:私有的,类成员只能类内使用
protected:保护的,类成员在类内以及子内中都可以使用
public:公共的,类成员在类内子类中都可以使用,只要是在定义类中都可以使用
*/
class PEOPLE
{
public:
/*构造函数,编译器默认进行提供
默认的构造函数没有返回值(不是void,是真的没有),函数名是
当前的类名,无参,函数体代码为空
在定义对象的时候自动调用,用来初始化类成员属性,构造函数允许多个
,他们是函数重载的关系
一旦我们手动了重构了构造函数,编译器将不再提供默认的无参的构造
{new 在}之前进行析构},如果实在main中,就是在return 中
*/
PEOPLE()
{
p_name = "老大";
}
PEOPLE(string name)
{
p_name = name;
p_age = 12;
p_note = nullptr;
p_note = new char[10];
}
PEOPLE(string name,int age)
{
p_name =name;
p_age = age;
p_note = nullptr;
p_note = new char[10];
}
/*
析构函数,编译器会默认提供
默认的构造函数:无返回值(不是void,是真的没有),函数名是当前的类名
,无参,函数体代码为空 析构函数只允许有一个,并且无参数
用来回收成员申请的额外空间,在对象声明周期结束前(对象回收前)自动调用
PEOPLE people1("laoda")当这个创建以后,程序输出之前就会对
这个进行析构函数的使用
*/
~PEOPLE()
{
if (p_note != 0)
{
delete []p_note;
p_note = nullptr;
}//对new创建出来的空间进行释放
cout << "使用了析构函数" << endl;
}
public:
string p_name;
char* p_note;
private:
int p_age;
protected:
bool p_sex;
public:
void p_eat()
{
cout << p_name << " 在吃饭呢 " << endl;
}
void p_setage(int age)
{
if (age <= 40 && age >= 10)
{
p_age = age;
}
p_age = 0;
}//可以通过设置一个岁数的范围,来防止瞎输内容,起到一个保护的作用
int p_getage()
{
return p_age;
}
int showage()
{
return p_age;
}
};
int main01()
{
PEOPLE people;//默认找到函数中的PEOPLE()这个,他将类中的成员都进行了赋值
people.p_name = "江焕龙";//将class中的数据设置成public才能访问
/*想要对私有的年龄进行更改,可以设置一个类内公共的函数people.p_setage(20), people.p_getage()*/
people.p_setage(20);
cout << people.p_getage() << endl;
PEOPLE people1("laoda",20);//默认找到函数中的PEOPLE(string name)这个
cout << people1.p_name << endl;
PEOPLE * p_str = new PEOPLE("laoer", 20);
p_str->p_name = "老三";
delete p_str;//在主函数中开放一个指针
p_str = nullptr;
return 0;
}#include <iostream>
#include <string>
using namespace std;
/*
类和对象
类:某一功能的数据以及算法的结合
c语言中的数据和算法是相互独立的,关联性不强
c++中的相关的数据以及结构进行封装形成结构体以及类,
在没有使用到真的数据的时候,结构体以及类都是一种虚拟的
当赋值了数据,数据才会有效,这个数据我们就称为是对象,
c++中的都是由各种类组成的,这就是面对对象
对类中的内容进行访问,要有访问修饰符
访问修饰符(3个):约束类成员的适用范围,默认的修饰方式是private
private:私有的,类成员只能类内使用
protected:保护的,类成员在类内以及子内中都可以使用
public:公共的,类成员在类内子类中都可以使用,只要是在定义类中都可以使用
*/
class PEOPLE
{
public:
/*构造函数,编译器默认进行提供
默认的构造函数没有返回值(不是void,是真的没有),函数名是当前的类名
,无参,函数体代码为空
在定义对象的时候自动调用,用来初始化类成员属性,构造函数允许多个,
他们是函数重载的关系
一旦我们手动了重构了构造函数,编译器将不再提供默认的无参的构造
{new 在}之前进行析构},如果实在main中,就是在return 中
*/
PEOPLE()
{
p_name = "老大";
}
PEOPLE(string name)
{
p_name = name;
p_age = 12;
p_note = nullptr;
p_note = new char[10];
}
PEOPLE(string name,int age)
{
p_name =name;
p_age = age;
p_note = nullptr;
p_note = new char[10];
}
/*
析构函数,编译器会默认提供
默认的构造函数:无返回值(不是void,是真的没有),函数名是当前的类名
,无参,函数体代码为空
析构函数只允许有一个,并且无参数
用来回收成员申请的额外空间,在对象声明周期结束前(对象回收前)自动调用
PEOPLE people1("laoda")当这个创建以后,程序输出之前就会对这个进行析构函数的使用
*/
~PEOPLE()
{
if (p_note != 0)
{
delete []p_note;
p_note = nullptr;
}//对new创建出来的空间进行释放
cout << "使用了析构函数" << endl;
}
public:
string p_name;
char* p_note;
private:
int p_age;
protected:
bool p_sex;
public:
void p_eat()
{
cout << p_name << " 在吃饭呢 " << endl;
}
void p_setage(int age)
{
if (age <= 40 && age >= 10)
{
p_age = age;
}
p_age = 0;
}//可以通过设置一个岁数的范围,来防止瞎输内容,起到一个保护的作用
int p_getage()
{
return p_age;
}
int showage()
{
return p_age;
}
};
int main01()
{
PEOPLE people;//默认找到函数中的PEOPLE()这个,他将类中的成员都进行了赋值
people.p_name = "江焕龙";//将class中的数据设置成public才能访问
/*想要对私有的年龄进行更改,可以设置一个类内公共的函数people.p_setage(20), people.p_getage()*/
people.p_setage(20);
cout << people.p_getage() << endl;
PEOPLE people1("laoda",20);//默认找到函数中的PEOPLE(string name)这个
cout << people1.p_name << endl;
PEOPLE * p_str = new PEOPLE("laoer", 20);
p_str->p_name = "老三";
delete p_str;//在主函数中开放一个指针
p_str = nullptr;
return 0;
}
t &b)
不是函数重载,俩个为同一个意思,但是使用函数指针的时候,可以对俩个进行分辨2.链表的封装
设计一个单向的链表,设置一个节点的类,在定义一个链的定义,并且增加链表的很多功能,可以直接进行使用
#include<iostream>
using namespace std;
/*
C++ 中类和结构体的区别:
1. 默认的访问修饰符不同,结构体 public 类: private
2. 默认的继承方式不同,结构体 public 类: private
*/
struct Node {
int val;//节点中的内容
Node* pNext;//定义一个指向下一节点的指针
Node(int v) {
val = v;
pNext = nullptr;
}//建立一个构造函数,对内容进行初始值赋值
};
class CMyList {//建立一个链表
private:
Node* m_pHead;
Node* m_pEnd;
int m_nSize;
public:
CMyList() {
m_pHead = nullptr;
m_pEnd = nullptr;
m_nSize = 0;
}
~CMyList() {
//遍历链表回收节点空间
Node* p_temp=nullptr;
while (m_pHead)//当链表不为空的时候
{
p_temp = m_pHead;
m_pHead = m_pHead->pNext;
delete p_temp;
p_temp = nullptr;
}
m_pHead = nullptr;
m_pEnd = nullptr;
m_nSize = 0;
}
public:
// 尾添加
void makeback(int v)
{
Node* pnode =new Node(v);
if (m_pHead)//非空链表
{
m_pEnd->pNext = pnode;
m_pEnd = pnode;
}
else//空链表
{
m_pHead = pnode;
m_pEnd = pnode;
}
m_nSize++;
}
//头删除
void delete_head()
{
if (m_pHead)//链表非空
{
if (m_pHead==m_pEnd)//只有一个节点
{
m_pHead = nullptr;
m_pEnd = nullptr;
}
else//多个节点
{
Node* p_type = m_pHead;
m_pHead = m_pHead->pNext;
delete p_type;
}
m_nSize--;
}
else//链表为空
{
cout << "链表为空" << endl;
}
}
//查看链表
void show_list()
{
if (m_pHead)//链表不为空
{
Node* p_show = m_pHead;
while (p_show)//当指针指向链表中的节点时候
{
cout << p_show->val << endl;
p_show = p_show->pNext;
}
}
else
{
cout << "链表为空" << endl;
}
}
//获取长度
int get_size()
{
return m_nSize;
}
};
int main() {
/*Node* pNode = new Node(10);
cout << pNode->val << endl;*/
CMyList mylist;
mylist.makeback(1);
mylist.makeback(2);
mylist.makeback(3);
mylist.makeback(4);
mylist.makeback(5);
mylist.show_list();
cout << mylist.get_size() << endl;
/*system("pause");*/
return 0;
}
3.建立一个马里奥的界面
建立一个奥利奥的界面,首先就需要考虑将使用什么变量,上下左右四个方向的变量,马里奥的坐标值以及行进的方向,建立一个马里奥的类,需要考虑我们需要什么一些的函数
onrun():一直运行,不断运行这个函数,可以在这个函数中建立一个不断循环,去读取键盘中我们按下的方向键,在对这个功能进行画面上的显示
oninit():对界面的内容进行初始化,对马里奥的图片进行链接,以及对马里奥的初始位置进行赋值对全局需要进行初始值的,都可以写在这部分的函数中
onpaint():对界面中的内容进行重绘,以及显示界面,在结束重绘
showmario():对mario正在行进的方向进行贴图,就是显示对应方向的马里奥的图片
movemario():读取键盘上的方向键,移动马里奥的图片
#include<easyx.h>
#include<conio.h>
#define ESC 29
#define DEF_UP 72
#define DEF_DOWN 80
#define DEF_LEFT 75
#define DEF_RIGHT 77
class Cmario
{
public://先把变量先设置一下
IMAGE m_imgup;
IMAGE m_imgdown;
IMAGE m_imgleft;
IMAGE m_imgright;
int m_x;
int m_y;
int m_direc;
public:
//对类中设置的变量进行初始赋值,这个赋值只是在函数未进行调用的时候进行赋值,函数中的赋值在后面写
Cmario()
{
//创建窗口
::initgraph(600, 600);//::意思是从全局中寻找这个函数,initgraph是系统中自带的
//设定窗口背景颜色
::setbkcolor(RGB(255, 255, 255));//RGB红绿蓝,显示什么颜色
::cleardevice();//对屏幕进行清屏
//初始化成员函数
/*//IMAGE是一个系统中设置的初始类,不用进行初始赋值
IMAGE m_imgup;
IMAGE m_imgdown;
IMAGE m_imgleft;
IMAGE m_imgright;
*/
int m_x = 0;
int m_y = 0;
int m_direc = 0;
}
~Cmario()
{
::closegraph;//关闭窗口
}
public:
void Oninit()//逻辑意义上的初始化,与程序业务逻辑相关
{
//IMAGE与磁盘中的图片进行绑定关联
::loadimage(&m_imgup, "./res/mali-up.bmp");
::loadimage(&m_imgdown, "./res/mali-down.bmp");
::loadimage(&m_imgleft, "./res/mali-left.bmp");
::loadimage(&m_imgright, "./res/mali-right.bmp");
//loadimage如果显示红线,项目属性-高级-字符集-使用多字符集
m_x = 100;
m_y = 100;
m_direc = DEF_RIGHT;
}
void onrun()
{
//onpaint();
while (1)
{
//判断方向键是否有按下的,如果按下,获取具体的数据
if (_kbhit())//不断扫描键盘是否有按键被按,头文件是 <conio.h>
{
int key = _getch();//获取具体的案件
//如果是ESC,程序退出,break循环
if (key == ESC)
{
break;
}
//调用人物移动的方法,将key串到人物移动的方法中
movemario(key, 10);
}
//调用重绘
onpaint();
Sleep(100);
}
}
void onpaint()
{
//批量重绘
::BeginBatchDraw();//开始批量重绘
//根据方向显示不同的图
showmario();
::EndBatchDraw();//结束批量绘图
}
void showmario()
{
::cleardevice();//对预留下的痕迹进行屏,也可放在onpaint()中的showmario之前
switch (m_direc)
{
case(DEF_UP):
{
::putimage(m_x, m_y, &m_imgup);
}
break;
case(DEF_DOWN):
{
::putimage(m_x, m_y, &m_imgdown);
}
break;
case(DEF_LEFT):
{
::putimage(m_x, m_y, &m_imgleft);
}
break;
case(DEF_RIGHT):
{
::putimage(m_x, m_y, &m_imgright);
}
break;
}
}
void movemario(int direct, int step)//移动,步长,每次移动的距离
{
switch (direct)
{
case(DEF_UP):
{
if (m_y-step >=0)
{
m_y -= step;
}
else
{
m_y = 0;
}
m_direc = DEF_UP;
break;
}
case(DEF_DOWN):
{
if (m_y + step <= 540)
{
m_y += step;
}
else
{
m_y =540;
}
m_direc = DEF_DOWN;
break;
}
case(DEF_LEFT):
{
if (m_x - step >= 0)
{
m_x -= step;
}
else
{
m_x = 0;
}
m_direc = DEF_LEFT;
break;
}
case(DEF_RIGHT):
{
if (m_x+step >= 0)
{
m_x+= step;
}
else
{
m_x = 540;
}
m_direc = DEF_RIGHT;
break;
}
}
}
};
int main()
{
Cmario mario;
mario.Oninit();
mario.onrun();
return 0;
}
4.对象的种类
#include<iostream>
using namespace std;
#include"标头.h"
//全局对象生命周期: 程序开始创建 - 程序退出(销毁)被回收
//作用域:整个应用程序,可跨文件使用
//CTest tst2;
//静态全局对象生命周期:程序开始创建 - 程序退出(销毁)被回收
//作用域:只能在当前文件进行使用,具有文件作用域
static CTest tst3;
//声明
extern CTest tst2;
CTest* PTST = nullptr;
void show()
{
static CTest tst4;//静态局部的,第一次调用包含这个对象的函数,被调用执行(被调用多次,也不会再被创建),这种的不会被析构
PTST = &tst4;
}
CTest play()
{
CTest tst6(40);
return tst6;
}
int main(){
cout<<"-------------"<<endl;
cout<< tst2.m_a<<endl;
extern int aa ;
aa = 10;
cout<<aa<<endl;
//tst3.m_a =10;
//CTest tst; //栈区局部对象,遇到函数的返回或者 } 生命周期结束,自动回收
//CTest * pTst = new CTest;
//delete pTst; //手动回收
//pTst = nullptr; //
//
CTest();//临时对象,生命周期仅限于当前行,遇到;结束
cout<<"==============="<<endl;
return 0;
}
5.对象的种类
#include <iostream>
using namespace std;
/*非静态类成员属性,属于对象,在定义对象时才存在,定义多个对象存在多分,彼此之间不影响
* 类成员函数:属于这个类,不属于对象(存在与否不依赖对象定义与否),在编译器就存在了,类成员函数只有一份
*
* this指针:当前类对象的指针,类中非静态成员函数的参数列表中。默认编译器加的一个隐藏的参数
* 在参数列表中的
* 作用:连接对象以及类成员
*
*
* 静态车成员函数与普通成员函数区别:静态成员函数没有隐藏this指针参数,不能使用普通的成员(成员属性+成员函数)
*
* 静态成员属性:不属于对象,属于类的只有一份,多个对象之间共享这个静态成员,在编译期就存在了,不依赖对象而存在
* 在类外进行初始化 类型 类名::变量名=初始化值
* 静态成员,在没有对象的时候,可以通过【类名::】调用,也可以通过对象去调用
*/
class CTEST
{
public:
int m_a=1;
int m_b;
static int m_c;//需要在外部进行初始化
void show()//Ctest * const this)//指向对象
{
this->m_a;//rhis指针,跟外部的p指针其实是一个
cout <<"this"<< this << endl;
int a = 1;
cout << a << endl;
}
void show(int b)
{
int m_c = b;
cout << m_c << endl;
cout << &(m_c) << endl;
}
static void get()
{
cout << m_c << endl;//使用静态成员属性合法,
}
};
int CTEST::m_c = 10;//对静态变量进行初始化
int main()
{
CTEST tst;
CTEST* p = new CTEST();
//cout << "p" << p << endl;
//p->show();
//cout << sizeof(tst) << endl;//为1 里面没有内容时候, 占位作用,表示当前对真是存在于内存当中
//cout << sizeof(tst) << endl;//4 只有int
//cout << &(tst.m_a) << endl;
//cout << &(tst.m_b) << endl;
tst.show(2);
cout << tst.m_c << endl;
//cout << sizeof(tst) << endl;//16.加上一个double (8),等位对齐,每个都是8,8总是16
}