C++复习封装(多验证)
实例化:
从栈实例化对象:系统自动回收
TV tv1;
从堆实例化对象:delete释放内存
TV *p = new TV();
TV *q = new TV[20];
delete p;
delete []q;
对象成员访问
栈:对象 加 .
int main()
{
TV tv;
tv.type = 0;
tv.changeVol();
return 0;
}
堆:指针 加 ->
int main()
{
TV *p = new TV();
p->type =0;
p->changeVol();
delete p;
p = NULL;
return 0;
}
String
初始化string对象:
string s1;
string s2(“ANC”);
string s3(s2);
string s4(n,‘c’); 将s4初始化为字符’c’的n个副本。
常用基础操作:
s.empty(); 空返回true,否则false
s.size(); 返回s中字符个数
s[n]; 返回s中位置为n的字符,位置从0开始
s1+s2 返回连接后的新串
s1 = s2 将s1内容替换为s2的副本
s1 == s2 相等返回true,否则false
字符串常量之间+是非法的,+两边必须至少有一个为string对象
而非常量"xxx"
类内定义和内联函数
内联函数:关键字inline:编译时将函数体代码和实参代替函数调用语句。必须是结构很逻辑比较简单的代码,才能保证效率快。
普通函数:main()调用普通函数->找到函数入口->运行函数的代码->结束后返回到主调函数。
类内定义就是成员函数的定义在类中。类内定义的成员函数(简单的)会自动看作inline函数。
类外定义是指成员函数的函数体写在类的外面:
1.同文件类外定义(类定义与成员函数定义在同一个文件中)
需要在每个函数前面用类名 加上 :: 来标识
2.分文件类外定义:
定义一个与类名(Car)相同名字的头文件(Car.h)
再在Car.cpp中加上#include “Car.h”
实现成员函数的定义同样是要在每个函数前面用类名 加上 :: 来标识。
内存分区
栈区:定义变量。内存由系统分配。
int x = 0;
int *p = NULL;
堆区:new分配的内存,需要自己管理。
int *p = new int[20];
全局区:存储全局变量及静态变量。
常量区:存储常量
string str = "hello";
代码区:存储逻辑代码的二进制
构造函数
class student
{
public:
Student(){}
Student(string name = "Jim")
private:
string m_strName;
};
int main()
{
Student stu1();
Student *p = NULL;
p = new Student();
return 0;
}
初始化列表:
class student
{
public:
Student():m_strName("Jim"),m_iAge(10){}
private:
string m_strName;
int m_iAge;
};
初始化列表先于构造函数执行。
初始化列表只能用于构造函数。
初始化列表可以同时初始化多个数据成员,速度高,效率快。
初始化列表的必要性:
类中的不变的成员变量(常量,比如PI),必须通过初始化列表。
拷贝构造函数:
定义格式:类名(const 类名& 变量名)
构造函数分为无参构造函数(默认构造函数)和有参构造函数(分为参数带默认值和参数不带默认值)。
还有相关的小点:
1.深、浅拷贝:
有指针类型的数据成员时,在main中 obj1 = obj2来创建对象对其初始化时需要在类中定义深拷贝构造函数(即需要将指针指向的内存中的变量一一赋值)
2.对象数组
…就是一下定义好多对象呗 new的时候 类名后面不是()而是[n]… n是数组中元素个数
3.对象指针:
指向对象的指针,指针指向的内存就是对象里第一个数据成员的地址,可以 p->来访问对象数据成员,也可以用(*p). 来访问,前者是指针,后者是对象。
4.对象成员指针:
某个类对象的指针作为另一个类的成员。可以初始化列表进行初始化(直接()里NULL就行),也可以进行普通的初始化,还可以m_a = new C(1,3);在用其构造函数堆中创建对象,但要注意这种需要在我们的当前类的析构函数里加上delete语句释放。
5.this指针:
指向对象自身数据的指针。 this指针就是&当前对象。在类中的方法中都隐藏了this指针参数,所以调用的时候也隐藏了this指针,实际上是存在的,由此不会产生对象错乱的情况。
6.const:
类的数据成员可以用const来修饰,基本数据类型的数据成员用const修饰时,需要用初始化列表来初始化给它一个不变的值。
class Coordinate
{
public:
Coordinate(int x,int y);
private:
const int m_iX;
const int m_iY;
};
Coordinate::Coordinate(int x, int y):m_iX(x),m_iY(y)
{
}
7.常对象成员:
一旦初始化就不能再修改的对象成员。
class Line
{
public:
Line(int x1, int y1, int x2, int y2);
private:
const Coordinate m_coorA;
const Coordinate m_coorB;
};
Line::Line(int x1,int y1, int x2, int y2):m_coorA(x1,y1),m_coorB(x2,y2)
{
}
int main{
Line *p = new Line(2.1.6,4);
delete p;
p = NULL;
return 0;
}
8.常成员函数:
常成员函数中不能修改成员函数的值。
class Coordinate
{
public:
Coordinate(int x, int y);
void changeX() const; //常成员函数和下面这个函数是互为重载
void changeX();
private:
int m_iX;
int m_iY;
};
void Coordinate::changeX()
{
m_iX = 20;
}
int main()
{
Coordinate coordinate(3,5);
coordinate.changeX(); //调用的是不带const的成员函数
return 0;
}
函数定义实际上隐藏了this指针,等价于:
void Coordinate::changeX(Coordinate *this)
{
this->m_iX = 20;
}
为什么函数类外定义的时候不在后面也加上const呢?
因为定义时加上const后,this指针就变成了常指针:const Coordinate *this
此时它指向的数据m_iX是不能被修改的,即this->m_iX = 20;会出错。
怎样能调用const修饰的成员函数呢?
int main()
{
const Coordinate coordinate(3,5); //定义一个常对象
coordinate.changeX(); //通过常对象调用const修饰的成员函数
return 0;
}
9.常指针,常引用:
在对象指针或对象引用前加上const。
对象引用可以直接赋值初始化,而对象指针需要给赋值对象加一个引用:
Coordinate coor(3,5);
Coordinate &coor2 = coor1;
Coordinate *pCoor = &coor1;
常引用或常指针只有一个读权限,而getX();函数中隐藏的this要求的是读写权限的参数,所以如果coor2.getX();或Pcoor->getY();会报编译错误。想要调用成员函数只能调用printInfo():
Coordinate coor(3,5);
const Coordinate &coor2 = coor1;
const Coordinate *pCoor = &coor1;
如果是下面这样:
Coordiante * const pCoor = &coor1;
那么pCoor就只能指向coor1这一个对象,不能指向其他对象。但指针是具有读写权限的,所以可以调用getY();