C++封装
封装:把一些信息封装起来,只暴露出用户关心的信息。通过访问限定符将想要暴露的暴露出来,想要隐藏的隐藏起来。
类和对象
对象实例化:
从栈中实例化:类的名字,对象名字
从堆中实例化:用new申请一块内存,用指针指向这快内存的地址。申请使用完之后要将内存释放置空掉(delete 指针 、指针=NULL)。
从栈上和从对上访问成员函数的方法:(左图上从栈上,右图是从堆上)
栈:
#include<iostream>` `using namespace std;` `class Coordinate{` `public:` `int x;` `int y;` `void printX(){` `cout<<x<<endl;` `}` `void printY(){` `cout<<y<<endl;` `}` `};` `int main(){` `Coordinate c;` `c.x=10;` `c.y=20;` `c.printX();` `c.printY();` `return 0;` `}
堆:
#include<iostream>
using namespace std;
class Coordinate{
public:
int x;
int y;
void printX(){
cout<<x<<endl;
}
void printY(){
cout<<y<<endl;
}
};
int main(){
``Coordinate *p=new Coordinate();
if(NULL==p){
return 0;
}
p->x=100;
p->y=200;
p->printX();
p->printY();
delete p;
p=NULL;
return 0;
}`
数据成员和成员函数
数据成员也叫属性。
成员函数也叫方法。
字符串类型
与java不同的是使用字符串需要引入string头文件;string首字母小写;字符串用双引号,字符使用单引号。
1、string s1;此时s1是一个空串。
2、string s2="wangjiaer";赋初始值。
3、string s3(s2);s3是s2的一个副本。
4、strings4(n,'c');s4初始化为字符‘c’的n个副本。
5、string的常用操作:
非法写法:string s=“hello”+“world”;
练习:
#include <iostream>
#include <string>
using namespace std;
/**
* 定义类:Student
* 数据成员:名字、年龄
*/
class Student
{
public:
// 定义数据成员名字 m_strName 和年龄 m_iAge
string m_strName;
int m_iAge;
};
int main()
{
// 实例化一个Student对象stu
Student stu;
// 设置对象的数据成员
stu.m_strName = "慕课网";
stu.m_iAge = 2;
// 通过cout打印stu对象的数据成员
cout << m_strName << " " << m_iAge<< endl;
return 0;
}
报错:倒数第三行m_strName 和 m_iAge没有定义。
原因:在main函数中我声明定义的``stu.m_strName = "慕课网"; stu.m_iAge = 2;
这个是对象stu的定义。而m_strName 和 m_iAge是没有定义的。按照要求 // 通过cout打印stu对象的数据成员
,正确写法是:
cout << stu.m_strName << " " << stu.m_iAge<< endl;
属性封装
面向对象的基本思想:对象在程序中的所有操作都转换成对函数的操作。
get/set方法:对私有属性进行操作。
练习:
include
include
using namespace std;
/**
- 定义类:Student
- 数据成员:m_strName
- 数据成员的封装函数:setName()、getName()
*/
class Student
{
public:
// 定义数据成员封装函数setName()
void setName(string _name){
m_strName=_name;
}
// 定义数据成员封装函数getName()
string getName(){
return m_strName;
}
//定义Student类私有数据成员m_strName
private:
string m_strName;
};
int main()
{
// 使用new关键字,实例化对象
Student *str = new Student();
// 设置对象的数据成员
str->setName("慕课网");
// 使用cout打印对象str的数据成员
cout<
// 将对象str的内存释放,并将其置空
delete str;
str=NULL;
return 0;
}
类内定义和内联函数
内联函数:inline;
类内定义:函数和函数体写在类的内部。
类内定义的成员函数,编译器会优先将其编译为inline函数。
类外定义:同文件类外定义,分文件类外定义
同文件类外定义:成员函数的定义在类外定义,但是需要声明是哪个类的方法。
分文件类外定义:将成员函数的声明写在一个与类名相同的头文件中(类名.h),在类中需要将该头文件引入,才可以定义头文件中的方法。
构造函数和析构函数
对象初始化:有且仅有一次或者根据条件初始化。
构造函数:初始化。在对象实例化时被自动调用。构造函数在初始化实例对象被调用且仅被调用一次。构造函数与类同名,没有返回值,可有多个重载形式,但是在实例化对象时候,只会用到一个构造函数。用户如果没有定义构造函数,编译器会自动生成一个构造函数。
在实例化对象时不需要传递参数的叫做默认构造函数。无参构造函数默认构造函数。
拷贝构造函数:
拷贝构造函数的参数是确定的,不能重载
析构函数
格式:~类名()
析构函数没有参数,不能被重载.
练习:
#include <iostream>
#include <string>
using namespace std;
/**
* 定义类:Student
* 数据成员:m_strName
* 无参构造函数:Student()
* 有参构造函数:Student(string _name)
* 拷贝构造函数:Student(const Student& stu)
* 析构函数:~Student()
* 数据成员函数:setName(string _name)、getName()
*/
class Student{
public:
Student(){
};
Student(string _name){
_name=m_strName;
}
Student(const Student& stu){
}
~Student(){
}
void setName(string _name){
m_strName=_name;
}
string getName(){
return m_strName;
}
private:
string m_strName;
};
int main(void)
{
// 通过new方式实例化对象*stu
Student *stu = new Student();
// 更改对象的数据成员为“慕课网”
stu->setName("慕课网");
// 打印对象的数据成员
cout<<stu->getName();
return 0;
}
上面之前一直没有输出的原因是,我定义Set方法的时候,写成了:
void setName(string name){
name=m_strName;
}
这是典型的错误.
正确应该是上面完整代码那样:
void setName(string _name){
m_strName=_name; //赋值语句
}
对象指针
对象指针:用一个指针指向对象。p->x=10;(*p).x=10;
类名 *p2=&p1;用p2的指针指向p1的地址。
this指针
如果参数和数据成员同名,编译器无法分辨。
this指针就是指向对象自身数据的指针。所以如果重名,用this指针就行。
每次调用成员函数都使用到了this指针。
this指针就是指向所在对象的地址。
对象数组
堆中实例化的数组需要手动销毁释放内存,在栈中实例化的数组,系统自动回收内存。
对象成员
存在的问题:
===================Coordinate.h
class Coordinate{
public:
Coordinate();
~Coordinate();
void setX(int x);
int getX();
void setY(int y);
int getY();
private:
int m_iX;
int m_iY;
};
======================Line.h
include "Coordinate.h"
class Line{
public:
Line();
~Line();
void setA(int x,int y);
void setB(int x,int y);
void printInfo();
private:
Coordinate m_coorA;
Coordinate m_coorB;
};
=====================Coordinate.cpp
include"Coordinate.h"
include
Coordinate::Coordinate(){
cout<<"coor()";
}
Coordinate::~Coordinate(){
cout<<"~coor()";
}
void Coordinate::setX(int x){
m_iX=x;
}
int Coordinate::getX(){
return m_iX;
}
void Coordinate::setY(int y){
m_iY=y;
}
int Coordinate::getY(){
return y;
}
========================Line.cpp
include"Line.h"
include
Line::Line(){
cout<<"line()";
}
Line::~Line(){
cout<<"~line()";
}
void Line::setA(int x,int y){
m_coorA.setX(x);
m_coorA.setY(y);
}
void Line::setB(int x,int y){
m_coorB.setX(x);
m_coorB.setY(y);
}
void Line::printInfo(){
cout<<m_coorA.getX()<<m_coorA.getY();
cout<<m_coorB.getX()<<m_coorB.getY();
}
===========================demo.cpp
include
include "Line.h"
using namespace std;
int main(){
Line *p=new Line();
delete p;
p=NULL;
return 0;
}
报错:
拷贝构造函数
浅拷贝:将值直接拷贝过去。这样会导致两个值指向的地址是用一个地址,导致释放内存的时候会出现释放两次,一定出问题。
深拷贝:为了解决上面的问题。在拷贝构造函数中,给要复制的对象申请内存。将传入的对象对应位置的内存拷贝到申请的内存中。
对象成员指针
一个指针在32为编译器下指向4个内存单元。
对象需要看他包含几个指针。
const
常对象成员和常成员函数
由const修饰的对象成员和成员函数。
互为重载:常成员函数和成员函数。调用名字相同的常成员函数时候需要在前面加上const。
常指针与常引用
没有const修饰的时候要求读写权限。
迷宫--算法
左手规则,右手规则。
(出口和入口不是同一个口)
迷宫类:二维 数组 0-墙/1-路
人类:人;人的朝向;当前位置;人前一个位置;人的速度;
构造函数,封装函数,朝不同方向前进的函数;开始函数;转弯函数。