类的定义方式:
// 以下包含的东西会导入到应用这个文件的文件
#include <string>
#include <iostream>
using namespace std;
/**
* .h文件 实现声明成员变量和成员函数作用
*/
class Liu {
public:
Liu(); // 无参构造( 默认) : 不用传参数的构造函数都是默认构造函数,所以有些构造函数所有参数都被初始化时,则会产生冲突,编译不过(初始化列表)
// Liu(string _strName = "liuguangxi00"); //等同于上面的Liu();
Liu(string _strName); //有参构造
Liu(string _strName,int age); //有参构造
// Liu(string _strName = "liugx", int age = 26, int money = 3000000); //初始化列表构造
// Liu(const Liu& gx);// 拷贝构造函数
void setName(string _strName);
string getName();
int getMoney();
int getWife();
private:
string m_strName;
int mAge;
const int mWife = 10;
const int mMoney = 50000;
};
#include "Liu.h"
/**
* C++不同文件类外定义代码演示
*/
Liu::Liu() {
Liu::m_strName = "liuguangxi";
Liu::setName("liugx");
cout << "Liu()" << endl;
}
Liu::Liu(string _strName) {
Liu::m_strName = _strName;
cout << "Liu(string _strName)" << endl;
}
Liu::Liu(string _strName, int age) {
Liu::m_strName = _strName;
Liu::mAge = age;
cout << m_strName << "_" << mAge << endl;
}
初始化列表的应用
//Liu::Liu(string _strName, int age, int money) :
// m_strName(_strName), mAge(age), mMoney(money) {
// cout << m_strName << "_" << mAge << "_" << mMoney << endl;
//}
//Liu::Liu(const Liu& gx):m_strName(_strName), mAge(age),mMoney(money){
// cout << "Liu拷贝构造函数被执行!!!" << endl;
//}
void Liu::setName(string _strName) {
Liu::m_strName = _strName;
}
string Liu::getName() {
return Liu::m_strName;
}
int Liu::getMoney() {
return mMoney;
}
int Liu::getWife() {
return mWife;
}
#include <iostream>
#include <string>
#include "Liu.h"
using namespace std;
/** 一、 对象是如何存储在内存中的?
* 内存分区
* 1、栈区 int i = 1;定义一个变量
* 2、堆区 int *p = new int[10];
* 3、全局区 存储的全局变量和静态变量
* 4、常量区 string str = "c++"
* 5、代码区 存储逻辑代码的二进制
*/
/**
* 二、 C++构造函数的初始化规则和特性与java完全相同
*/
/**
* 三 、与java不同的是,C++构造函数存在初始化列表
*/
int main() {
Liu liu;
cout<< liu.getName() << endl;
Liu liu0("liugx00");
cout<< liu0.getName() << endl;
return 0;
}
构造函数初始化列表:
// 以下包含的东西会导入到应用这个文件的文件
#include <string>
#include <iostream>
using namespace std;
/**
*
*/
class Liu {
public:
Liu(string _strName = "liugx", int age = 26, int money = 3000000); //初始化列表构造
private:
string m_strName;
int mAge;
// const int mWife(10);
const int mWife = 10; // 已赋值,不能用构造函数初始化列表方式进行重新赋值
const int mMoney;
};
#include "Liu.h"
//方式一、初始化列表的使用方式
Liu::Liu(string _strName, int age, int money) :
m_strName(_strName), mAge(age), mMoney(money) {
cout << m_strName << "_" << mAge << "_" << mMoney << "_" << mWife<< endl;
}
//方式二、普通方式进行属性的初始化
//Liu::Liu(string _strName, int age, int money) {
// m_strName = _strName;
// mAge = age;
// mMoney = money; //普通初始化与初始化列表区别就在于此行代码不通过编译器,因为初始化列表的赋值是在构造函数的执行之前赋值的
// cout << m_strName << "_" << mAge << "_" << mMoney << "_" << mWife<< endl;
//}
#include <iostream>
#include "Liu.h"
using namespace std;
/**
* 初始化列表所有参数都必须要被初始化,构造函数初始化列表就是默认构造函数,即无参构造函数之一(如果两者同时存在,编译时编译器无法分辨)
*
* 构造函数初始化列表与函数特性章节所讲内容类似,可供参考,与普通函数采用函数参数默认值进行赋值时最大的区别就是,
* 采用普通函数默认参数值进行赋值时不能赋值给const修饰过的常量,
* 而采用初始化列表则可以赋值给const修饰过的常量(在常量还未赋值之前进行初始化列表赋值)
*
* 初始化列表特性
* 1、初始化列表执行先于构造函数
* 2、初始化列表只能用于构造函数
*
* 初始化列表是写在函数右边的。示例代码:Liu::Liu(string _strName, int age, int money) :
m_strName(_strName), mAge(age), mMoney(money){}
*/
int main() {
Liu liu;
Liu liugx("liuguangxi",27);
return 0;
}
拷贝构造函数:
// 以下包含的东西会导入到应用这个文件的文件
#include <string>
#include <iostream>
using namespace std;
/**
* 遗留问题点:若构造函数初始化列表去初始化的参数中有被const修饰过的参数,则拷贝构造函数不能通过编译
*/
class Liu {
public:
// Liu();
Liu(string _strName = "liugx", int age = 26, int money = 3000000); //初始化列表构造
// 拷贝构造函数定义格式:类名(const 类名& 变量名)
Liu(const Liu&liu); // 拷贝构造函数
private:
string m_strName;
int mAge;
const int mWife = 10;
int mMoney;
// const int mMoney = 10; //如果加上const,拷贝构造函数既然报错???
/**
* 复写了拷贝构造函数 即是这个类是被const修饰过?
*/
};
#include "Liu.h"
//初始化列表的应用
Liu::Liu(string _strName, int age, int money) :
m_strName(_strName), mAge(age), mMoney(money) {
cout << m_strName << "_" << mAge << "_" << mMoney << endl;
}
//Liu::Liu() {
// cout << "Liu()" << endl;
//}
Liu::Liu(const Liu&liu){
cout << "Liu拷贝构造函数被执行!!!" << endl;
}
#include <iostream>
#include <string>
#include "Liu.h"
using namespace std;
void test(Liu liu){}
int main() {
Liu liu;
Liu liug = liu;
Liu liugx(liu);
// 以上理论上是执行三次Liu的构造函数,但事实上是只执行了一次,因此出现了拷贝构造函数
// 拷贝构造函数定义格式:类名(const 类名 &变量名)
// 如果没有定义拷贝构造函数,则系统自动生成一个默认的拷贝构造函数
// 当采用直接初始化或者复制初始化实例对象时系统会自动调用拷贝构造函数
test(liu);
return 0;
}
析构函数:
#include <string>
#include <iostream>
using namespace std;
class Teacher {
public:
Teacher(); // 无参构造( 默认)
Teacher(string _strName); //有参构造
Teacher(const Teacher&tea);// 拷贝构造函数
~Teacher(); //析构构造(对象被销毁时回调)
void setName(string _strName);
// 定义数据成员封装函数getName()
string getName();
//定义Student类私有数据成员m_strName
private:
string m_strName;
};
#include "Teacher.h"
Teacher::Teacher() {
Teacher::m_strName = "luke";
cout << "Teacher()" << endl;
}
Teacher::Teacher(string _strName) {
Teacher::m_strName = _strName;
cout << "Teacher(string _strName)" << endl;
}
Teacher::Teacher(const Teacher&tea){
cout << "拷贝构造函数被执行!!!" << endl;
}
Teacher::~Teacher() {
cout << "~Teacher()" << endl;
}
// 定义数据成员封装函数setName()
void Teacher::setName(string _strName) {
Teacher::m_strName = _strName;
}
// 定义数据成员封装函数getName()
string Teacher::getName() {
return Teacher::m_strName;
}
#include <iostream>
#include "Teacher.h"
using namespace std;
/**
* 1、析构函数如果没有自定义,则系统自动生成
*
* 2、析构函数在对象销毁时自动调用,类似于Android中activity的ondestroy()
*
* 3、析构函数于构造函数一样没有返回值,但是没有参数,即是不能重载该函数
*/
int main() {
Teacher tea;
Teacher t = tea;
return 0;
}
// 以下包含的东西会导入到应用这个文件的文件
#include <string>
#include <iostream>
using namespace std;
/**
* .h文件 实现声明成员变量和成员函数作用
*/
class Liu {
public:
// Liu(); // 无参构造( 默认)
// Liu(string _strName); //有参构造
Liu(string _strName = "liugx", int age = 26, int money = 3000000); //初始化列表构造
// Liu(const Liu& gx);// 拷贝构造函数
void setName(string _strName);
string getName();
int getMoney();
int getWife();
private:
string m_strName;
int mAge;
const int mWife = 10;
const int mMoney;//若要改变常量,必须要在初始化列表中进行初始化时才能改变
};
#include "Liu.h"
/**
* C++不同文件类外定义代码演示
*/
Liu::Liu(string _strName, int age, int money) :
m_strName(_strName), mAge(age), mMoney(money) {
cout << m_strName << "_" << mAge << endl;
}
void Liu::setName(string _strName) {
Liu::m_strName = _strName;
}
string Liu::getName() {
return Liu::m_strName;
}
int Liu::getMoney() {
return mMoney;
}
int Liu::getWife() {
return mWife;
}
#include <iostream>
using namespace std;
/**
* 定义类:Student
* 数据成员:m_strName
* 数据成员的封装函数:setName()、getName()
*/
class Student {
private:
string m_strName;//定义Student类私有数据成员m_strName
public:
int mAge;
// 定义数据成员封装函数setName()
void setName(string _strName) {
m_strName = _strName;
}
// 定义数据成员封装函数getName()
string getName() {
return m_strName;
}
};
int main() {
Student std;
std.mAge = 26;
cout << std.mAge << endl;
// 使用new关键字,实例化对象
Student *str = new Student();
// 设置对象的数据成员
str->setName("深圳人");
// 使用cout打印对象str的数据成员
cout << str->getName() << endl;
// 将对象str的内存释放,并将其置空
delete str;
str = NULL;
return 0;
}
对象指针:
#include <iostream>
using namespace std;
class Coordinate {
public:
int mX;
int mY;
};
int main() {
/**
* 堆方式指针
*/
// 写法方式一
Coordinate *p = new Coordinate();
if (NULL == p) {
return 0;
}
p->mX = 10; //(*p).mX = 10;
p->mY = 20; //(*p).mY = 20;
cout << (*p).mX << endl;
cout << (*p).mY << endl;
delete p;
p = NULL;
// 写法方式二
Coordinate *p1 = NULL;
p1 = new Coordinate;
(*p1).mX = 10;
delete p1;
p1 = NULL;
/**
* 栈方式指针
*/
Coordinate p2;
Coordinate *p3 = &p2;
p3->mX = 10;
p3->mY = 18;
cout << p2.mX << endl;
cout << p2.mY << endl;
return 0;
}
对象成员:
#include <iostream>
#include "Coordinate.h"
using namespace std;
class Line {
public:
// Line();
Line(int x1,int y1,int x2,int y2);
~Line();
// void setA(int x,int y);
// void setB(int x,int y);
Coordinate getCoorA();
Coordinate getCoorB();
private:
Coordinate m_A;
Coordinate m_B;
};
#include "Line.h"
//Line::Line(){
// cout << "Line()" << endl;
//}
Line::Line(int x1, int y1, int x2, int y2) :
m_A(x1, y1), m_B(x2, y2) {
cout << "Line(int x1, int y1, int x2, int y2)" << endl;
}
Line::~Line() {
cout << "~Line()" << endl;
}
Coordinate Line ::getCoorA(){
return m_A;
}
Coordinate Line ::getCoorB(){
return m_B;
}
#include <iostream>
using namespace std;
class Coordinate {
public:
// Coordinate();
Coordinate(int x, int y);
~Coordinate();
void printXY();
void setX(int x);
void setY(int y);
int getX();
int getY();
private:
int mX;
int mY;
};
#include "Coordinate.h"
Coordinate::Coordinate(int x, int y) :
mX(x), mY(y) {
cout << "Coordinate()" << endl;
}
Coordinate::~Coordinate() {
cout << "~Coordinate()" << endl;
}
void Coordinate::printXY() {
cout << "Coordinate.x = " << mX << endl;
cout << "Coordinate.y = " << mY << endl;
}
void Coordinate::setX(int x) {
mX = x;
}
int Coordinate::getX() {
return mX;
}
void Coordinate::setY(int y) {
mY = y;
}
int Coordinate::getY() {
return mY;
}
#include <iostream>
#include "Line.h"
using namespace std;
int main() {
/**
* 包装汽车概念理解:实例化Line时会先去实例化Line里面的对象成员Coordinate,
* 销毁则是与创建的过程相反,先销毁Line再销毁Coordinate
*/
Line *line = new Line(1,2,5,3);
if (NULL == line) {
return 0;
}
line->getCoorA().printXY();
line->getCoorB().printXY();
delete line;
line = NULL;
cout << "对象成员" << endl;
return 0;
}
对象成员指针:
#include <iostream>
#include "Coordinate.h"
using namespace std;
class Line {
public:
// Line();
Line(int x1,int y1,int x2,int y2);
~Line();
// void setA(int x,int y);
// void setB(int x,int y);
Coordinate getCoorA();
Coordinate getCoorB();
private:
Coordinate *m_A;
Coordinate *m_B;
};
#include "Line.h"
//Line::Line(){
// cout << "Line()" << endl;
//}
//Line::Line(int x1, int y1, int x2, int y2) :
// m_A(x1, y1), m_B(x2, y2) {
// cout << "Line(int x1, int y1, int x2, int y2)" << endl;
//}
Line::Line(int x1, int y1, int x2, int y2) {
m_A = new Coordinate(x1, y1);
m_B = new Coordinate(x2, y2);
cout << "Line(int x1, int y1, int x2, int y2)" << endl;
}
Line::~Line() {
delete m_A;
m_A = NULL;
delete m_B;
m_B = NULL;
cout << "~Line()" << endl;
}
Coordinate Line::getCoorA() {
return *m_A;
}
Coordinate Line::getCoorB() {
return *m_B;
}
#include <iostream>
using namespace std;
class Coordinate {
public:
// Coordinate();
Coordinate(int x, int y);
~Coordinate();
void printXY();
void setX(int x);
void setY(int y);
int getX();
int getY();
private:
int mX;
int mY;
};
#include "Coordinate.h"
Coordinate::Coordinate(int x, int y) :
mX(x), mY(y) {
cout << "Coordinate()" << endl;
}
//Coordinate::Coordinate(int x, int y) {
// mX = x;
// mY = y;
// cout << "Coordinate()" << endl;
//}
Coordinate::~Coordinate() {
cout << "~Coordinate()" << endl;
}
void Coordinate::printXY() {
cout << "Coordinate.x = " << mX << endl;
cout << "Coordinate.y = " << mY << endl;
}
void Coordinate::setX(int x) {
mX = x;
}
int Coordinate::getX() {
return mX;
}
void Coordinate::setY(int y) {
mY = y;
}
int Coordinate::getY() {
return mY;
}
#include <iostream>
#include "Line.h"
using namespace std;
int main() {
Line *line = new Line(1, 2, 5, 3);
if (NULL == line) {
return 0;
}
line->getCoorA().printXY();
line->getCoorB().printXY();
delete line;
line = NULL;
cout << sizeof(line)<< endl;// 指针大小4
cout << sizeof(Line)<< endl;// 类的大小(类里面有两个指针)8
cout << "对象成员指针:即Line里面的成员对象Coordinate是指针类型的" << endl;
return 0;
}
对象数组:
#include <iostream>
using namespace std;
class Coordinate {
public:
Coordinate();
~Coordinate();
public:
int mX;
int mY;
};
#include "Coordinate.h"
Coordinate::Coordinate() {
cout << "Coordinate()" << endl;
}
Coordinate::~Coordinate() {
cout << "~Coordinate()" << endl;
}
#include <iostream>
#include "Coordinate.h"
using namespace std;
int main() {
Coordinate c[3];
c[0].mX = 10;
cout << "c[0].mX = " << c[0].mX << endl;
Coordinate *coor = new Coordinate[3];
if (NULL == coor) {
return 0;
}
// 指针方式访问元素
coor[0].mX = 15;
coor->mY = 30;
(coor + 1)->mY = 60;
cout << "coor[0].mX = " << coor[0].mX << endl;
cout << "coor[0].mY = " << coor[0].mY << endl;
cout << "coor[1].mY = " << coor[1].mY << endl;
coor++; //注意指针此时已经指向第1位元素下标
coor->mX = 0;
cout << "coor[1].mX = " << coor->mX << endl;
// 因为上面执行了coor++,所以直接delete无法释放之前申请的内存,必须要跟申请时的内存段保持一致
coor--;
delete[] coor;
coor = NULL;
return 0;
}
对象的深拷贝和浅拷贝:
#include <iostream>
using namespace std;
// 计算数组长度
template<class T>
int length(T& arr) {
//cout << sizeof(arr[0]) << endl;
//cout << sizeof(arr) << endl;
return sizeof(arr) / sizeof(arr[0]);
}
/**
* 浅拷贝demo class
*/
class Array {
public:
Array() {
mConut = 5;
mpArr = new int[mConut];
cout << "Array()" << endl;
}
Array(const Array&arr) {
mConut = arr.mConut;
mpArr = arr.mpArr;
cout << "&Array()" << endl;
}
~Array() {
delete[] mpArr;
mpArr = NULL;
cout << "~Array()" << endl;
}
void print() {
cout << "_mConut = " << mConut << endl;
cout << "_mpArr.length = " << length(mpArr) << endl;
}
void printAddr() {
cout << "mpArr = " << mpArr << endl;
}
int getCount() {
return mConut;
}
private:
int *mpArr;
int mConut = 6;
};
/**
* 深拷贝demo class
*/
class ArrayS {
public:
ArrayS() {
mConut = 5;
mpArr = new int[mConut];
cout << "ArrayS()" << endl;
}
ArrayS(const ArrayS&arrs) {
mConut = arrs.mConut;
// mpArr = arrs.mpArr;
mpArr = new int[mConut]; //重新开辟一块内存出来
for (int i = 0; i < mConut; i++) {
mpArr[i] = arrs.mpArr[i];
}
cout << "&ArrayS()" << endl;
}
~ArrayS() {
delete[] mpArr;
mpArr = NULL;
cout << "~ArrayS()" << endl;
}
void print() {
cout << "_mConut = " << mConut << endl;
cout << "_mpArr.length = " << length(mpArr) << endl;
}
void printAddr() {
cout << "mpArr = " << mpArr << endl;
}
int getCount() {
return mConut;
}
private:
int *mpArr;
int mConut = 6;
};
/**
* 拷贝构造函数的深浅拷贝
*
* 注意:与java不同,对象的赋值,两个对象不是等价的,
*
* 属性成员若有初始值则属性成员会等价赋值,若未赋值,则值是未知数,属性成员不等于另外一个对象的属性成员,需要去拷贝构造函数手动赋值
*
* 对象赋值,被赋值的对象不执行构造函数,只执行拷贝构造函数
*/
int main() {
/**
* 1、浅拷贝:简单的将值拷贝
* 2、深拷贝:需要将拷贝值拷贝到当前对象开辟的内存块中
*
* arr2和arr1的数据成员mpArr指针都是指向同一块内存,在我们销毁arr1的时候会去释放mpArr,销毁arr2的时候也会去释放mpArr
* 那么同一块内存被释放两次 ,则计算机会崩溃
*
* 正确做法是要为arr2的mpArr指针重新开辟新的内存块,即是深拷贝
*
* 深拷贝实际上就是要考虑到面向过程的变量或者说是内存块
*/
// 浅拷贝 同一块内存释放了2次
Array arr1;
Array arr2 = arr1;
// arr1.print();
// arr2.print();
arr1.printAddr();
arr2.printAddr();
cout << "arr2_mConut = " << arr2.getCount() << endl;
// 深拷贝
ArrayS arrS1;
ArrayS arrS2 = arrS1;
arrS1.printAddr();
arrS2.printAddr();
return 0;
}
this指针的应用:
#include <iostream>
using namespace std;
class Array {
public:
Array() {
cout << "Array()" << endl;
}
~Array() {
cout << "~Array()" << endl;
}
Array(Array&arr) {
cout << "&Array()" << endl;
}
void setLen(int len) {
this->len = len;
}
int getLen() {
return this->len;
}
Array print1() { // 注意:看打印信息可知拷贝构造函数被调用一次,析构函数多执行一次,说明返回出去一个临时的对象
cout << " print1()" << endl;
return *this; //返回的this是一个指针,this不是一个对象
}
Array& print2() { // 返回的是一个对象的引用,则操作的是同一个对象
cout << " print2()" << endl;
return *this;
}
Array* print3() { // 返回的是一个对象的指针,则操作的也是同一个对象
cout << " print3()" << endl;
return this;
}
void printAddr() { //输出当前对象的内存地址
cout << this << endl;
}
private:
int len;
};
/** 一、 对象是如何存储在内存中的?
* 内存分区
* 1、栈区 int i = 1;定义一个变量
* 2、堆区 int *p = new int[10];
* 3、全局区 存储的全局变量和静态变量
* 4、常量区 string str = "c++"
* 5、代码区 存储逻辑代码的二进制
*/
/**
* this指针的应用,与java中的this类似
*
* this指针默认已经在每个函数的参数列表
*
* A a1
* A a2
* A a3
* 我们用对象a1,a2,a3调用类A中的同一个方法时 ,实际上在内存管理的代码区中只存储了一次这个方法的二进制逻辑代码,
* 但是为什么能区分当前是执行哪个对象的这个方法?因为方法参数列表中默认有代表当前对象的this指针
*
*
*/
int main() {
Array arr1;
arr1.setLen(10);
cout << " len " << arr1.getLen() << endl;
arr1.print1().setLen(5);//不能改变arr1的len值
cout << " len " << arr1.getLen() << endl;
arr1.print2().setLen(5);
cout << " len " << arr1.getLen() << endl;
arr1.print3()->setLen(6);
cout << " len " << arr1.getLen() << endl;
arr1.printAddr();
cout << &arr1 << endl;
return 0;
}