学习教程:https://www.imooc.com/learn/382
- 从栈实例化对象
//定义:
class TV
{
public:
char name[20];
int type;
void changeVol();
void power();
};
int main()
{
//调用:
TV tv;
YV tv[20];
//访问:
tv.type = 0;
tv.changeVol();
return 0;
}
- 从堆实例化对象
//定义:
class TV
{
public:
char name[20];
int type;
void changeVol();
void power();
};
int main()
{
//调用:
TV*p = new TV();
TV*q = new TV[20];
//todo
//访问:
p->type = 0;
p->changeVol();
//释放:
delete p;
delete []q;
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 coor;
//调用:
coor.x = 10;
coor.y = 20;
coor.printx();
coor.printy();
//堆:
//定义:
Coordinate *co = new Coordinate();
if (co == NULL)
{
//申请空间失败
return 0;
}
//调用:
co->x = 100;
co->y = 200;
co->printx();
co->printy();
//释放(堆的):
delete co;
co = NULL;
return 0;
}
- string
头文件: #include <string>
举例使用:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
cout << "input name:" << endl;
getline(cin, name);
if (name.empty()) //用到了string的empty()
{
cout << "null" << endl;
return 0;
}
if (name == "imooc") //用到了string的判定相等
{
cout << "is imooc" << endl;
}
cout << "hello" + name << endl; //字符串+string
cout << "length:" << name.size() << endl; //用到了string的size()
cout << "first letter:" << name[0] << endl; //用到了string的返回字符个数
return 0;
}
- 封装
左图是普通的封装,右图是有限定的封装(满足条件才赋值)
右图更方便,例:给age赋1000,显然不合理,按右图,不满足条件,就不会赋值了,省事
图中,m_iWheelCount指轮子的个数,这里只希望被读,不希望被改变
举例:
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
void setName(string name)
{
strName = name;
}
string getName()
{
return strName;
}
void setGender(string gender)
{
strGender = gender;
}
string getGender()
{
return strGender;
}
int getScore()
{
return iScore;
}
void initScore() //初始化
{
iScore = 0;
}
void study(int score)
{
iScore += score;
}
private:
string strName;
string strGender;
int iScore;
};
int main()
{
Student stu;
stu.setName("zhangsan");
stu.setGender("男");
stu.initScore();
stu.study(3);
stu.study(2);
cout << stu.getName() << " " << stu.getGender() << " " << stu.getScore() << endl;
return 0;
}
类外定义
类内定义的成员函数,编译器会将其优先编译为类内函数。不会将“inline”写出来,但会以“inline”的方式优先编译,对复杂的成员函数,无法编译成内联函数的,再编译成普通的函数
类外定义:指成员函数的函数体写在类的外面
同文件类外定义:指成员函数虽然定义在类的外面,但其定义与类的定义在同一个文件中
分文件类外定义(常用):
同文件类外定义举例:
#include <iostream>
#include <string>
using namespace std;
class Teacher
{
public:
void setName(string _name);
string getName();
void setGender(string _gender);
string getGender();
void setAge(int _age);
int getAge();
void teach();
private:
string strName;
string strGender;
int iAge;
};
void Teacher::setName(string _name)
{
strName = _name;
}
string Teacher::getName()
{
return strName;
}
void Teacher::setGender(string _gender)
{
strGender = _gender;
}
string Teacher::getGender()
{
return strGender;
}
void Teacher::setAge(int _age)
{
iAge = _age;
}
int Teacher::getAge()
{
return iAge;
}
void Teacher::teach()
{
cout << "上课" << endl;
}
int main()
{
Teacher t;
t.setName("zhangsan");
t.setGender("男");
t.setAge(30);
cout << t.getName() << " " << t.getGender() << " " << t.getAge() << " " <<endl;
t.teach();
return 0;
}
以上例子改为分文件类外定义:
把class 定义放到Teacher.h文件(自己新建,记得加上头文件)
set get等方法实体还是留到在Teach.cpp文件(即上述例子的文件)
cpp文件加一句#include "Teacher.h"
对象结构
栈区:内存由系统来进行操作,无论是分配还是回收,都不需要程序员关心
堆区:由程序员管理,分配用new,回收用delete
定义时不占内存,实例化为car1、car2、car3后,每个对象都会在栈上开辟一段内存,用来存储各自的数据,逻辑代码放在代码区,谁需要谁就去调用,找到相应的代码入口,就可以执行相应的代码程序
对象初始化
构造函数
将初始化的代码写在构造函数内,就能初始化数据。
构造函数在实例化对象时,调用且仅被调用一次。
构造函数与类同名
构造函数没有返回值
构造函数可以有多个重载形式,重载的时候要遵循重载函数的规则
实例化对象时,即使有多个构造函数,使用的时候也只用到一个构造函数
当用户没有定义构造函数时,编译器自动生成一个构造函数
无参构造函数:
有参构造函数:
重载构造函数:
综合举例:
用VS,在同一个项目下
Teacher.h文件:
#include <iostream>
#include <string>
using namespace std;
class Teacher
{
public:
Teacher(); //无参构造函数
Teacher(string name, int age = 10); //有参构造函数 ,这里给年龄设了默认值,如果后面没有给年龄赋值,就用默认值
//如果全部都设默认值,那 Teacher() 就不知道是调用无参构造函数还是调用有参且使用默认值。
void setName(string _name);
string getName();
void setAge(int _age);
int getAge();
private:
string strName;
int iAge;
};
Teacher.cpp文件
#include <iostream>
#include <string>
#include "Teacher.h"
using namespace std;
Teacher::Teacher()
{
strName = "zhang";
iAge = 35;
cout << "Teacher()" << endl;
}
Teacher::Teacher(string name, int age)
{
strName = name;
iAge = age;
cout << "Teacher(string name,int age)" << endl;
}
void Teacher::setName(string _name)
{
strName = _name;
}
string Teacher::getName()
{
return strName;
}
void Teacher::setAge(int _age)
{
iAge = _age;
}
int Teacher::getAge()
{
return iAge;
}
demo.cpp文件:
#include <iostream>
#include <string>
#include "Teacher.h"
using namespace std;
int main()
{
Teacher t1; //调用无参构造函数
Teacher t2("Li", 23); //调用有参构造函数
Teacher t3("wang"); //调用有参构造函数,但不给年龄赋值,此时会用默认值 => 说明构造函数除了重载,还可以给参数赋默认值
//检查是否 用内存存了数据
cout << t1.getName() << " " << t1.getAge() << endl;
cout << t2.getName() << " " << t2.getAge() << endl;
cout << t3.getName() << " " << t3.getAge() << endl;
return 0;
}
运行demo.cpp文件
默认构造函数
int main()
{
Student stu1(); //从栈中实例化对象
Student *p = NULL;
p = new Student(); //从堆中实例化对象,并用指针指向他
return 0;
}
两种实例化对象的方法,调用的构造函数都不用传参数,对于这样的调用形式,在定义构造函数时,可以有不同方式
class Student
{
public:
Student(){} //这样定义,构造函数本身就没有参数
Student(string name = "zhang")
private:
string strName;
以上两种定义方式,在实例化Student对象时,都不用给构造函数传递形参
默认构造函数:在实例化对象时,不需要传递参数的构造函数
以上两个都是默认构造函数
构造函数初始化列表:
红色句子为初始化列表
格式:
构造函数后加 : 多个成员用 , 隔开
赋值用()不用=
初始化列表特性:
初始化列表先于构造函数执行
初始化列表只能用于构造函数
初始化列表可以同时初始化多个数据成员
举例说明初始化列表存在的必要性:
class Circle
{
public:
Circle(){dPi = 3.14} //因为dPi是const修饰的常量,不可以被赋值,此句会引起报错,是错的
Circle():dPi(3.14) {} //用初始化列表赋初值,是对的
private:
const double dPi; // pI是不变的数,设为const修饰的常量
举例示范:
用VS,同一个项目下:
Teacher.h
#include <iostream>
#include <string>
using namespace std;
class Teacher
{
public:
Teacher(string name = "zhang" , int age = 10 , int m = 100); //默认构造函数
void setName(string _name);
string getName();
void setAge(int _age);
int getAge();
int getMax();
private:
string strName;
int iAge;
const int iMax; //学生最大数量
};
Teacher.cpp
#include <iostream>
#include <string>
#include "Teacher.h"
using namespace std;
Teacher::Teacher(string _name , int _age,int m):strName(_name),iAge(_age),iMax(m)
{
//iMax = m; //iMax是const修饰的常量,如果在这里初始化,会报错
cout << "Teacher(string _name , int _age)" << endl; //体现函数被调用
}
int Teacher::getMax()
{
return iMax;
}
void Teacher::setName(string _name)
{
strName = _name;
}
string Teacher::getName()
{
return strName;
}
void Teacher::setAge(int _age)
{
iAge = _age;
}
int Teacher::getAge()
{
return iAge;
}
demo.cpp
#include <iostream>
#include <string>
#include "Teacher.h"
using namespace std;
int main()
{
Teacher t1; //有默认构造函数,如此语句这样定义,则输出的都是默认值,其中max是const修饰的常量
cout << t1.getName() << " " << t1.getAge() << " " << t1.getMax() << endl;
Teacher t2("wang", 22,150);
cout << t2.getName() << " " << t2.getAge() << endl;
return 0;
}
当构造函数没有参数时,也叫作默认构造函数
“一个类至少有一个默认构造函数”(X)
在申明类时可以不写构造函数,这样这个类就没有默认构造函数了,只是在编译的时候会自动帮我们生成一个构造函数。
当构造函数有参数,但每个参数都有默认值时,也成为默认构造函数
当实例化对象时,如果不使用任何参数,则调用的是默认构造函数
举例:
//定义:
class Student
{
public:
Student() //默认构造函数
{
cout <<"Student" ;
}
private:
string strName;
};
//实现:
int main()
{
Student stu1;
Student stu2 = stu1; //使stu2在实例化的过程中拥有了stu1的值
Student stu3(stu1); //使stu3在实例化的过程中拥有了stu1的值
return 0;
}
以上代码的结果,仅输出一行Student
实例化了三个对象,之前说过,实例化对象一定会调用构造函数。后两个对象调用的是 拷贝构造函数
无参构造函数就是默认构造函数。
有参构造函数,如果所有参数都带默认值,那么就是默认构造函数