文章目录
类和对象
什么是对象
如何描述对象
面向对象编程
什么是类
类的定义和实例化
类的语法形式
对象的创建和销毁
构造函数和初始化表
代码示例
类和对象
什么是对象
万物皆对象,任何一种事物都可以看做是对象。
如何描述对象
通过对象的属性(名词、数量词、形容词)和行为(动词)来描述对象。
例如:描述冰箱对象
- 属性:品牌、容量、颜色、功耗。。。。
- 行为:冷冻、冷藏、装东西。
面向对象编程
对自然世界中对象的观察引入到编程实践的一种理念和方法,这种方法称为“数据抽象”,即在描述对象时把细节的东西剥离出去,只考虑一般性的、有规律性的、统一性的东西。
什么是类
类是将多个对象的共性提取出来定义的一种新的数据类型,是对对象属性和行为的抽象描述。
现实世界到类到编程世界
具体对象–抽象–>属性/行为–实例化–>具体对象
类的定义和实例化
类的语法形式
struct/class 类名:继承方式 基类{ 访问控制限定符: 类名(形参表):初始化表{...}//构造函数 ~类名(void){...} //析构函数 返回类型 函数名(形参表){} //成员函数 数据类型 变量名;//成员变量 };
访问控制限定符:影响类中成员的访问位置
- public:公有成员,在任何位置都可以访问。
- private:私有成员,只有类的内部才能访问。
- protected:保护成员。
构造函数(constructor)
语法:
class 类名{ 类名(构造形参表){ //主要负责初始化对象,即初始化成员变量 } };
- 函数名与类名相同,没用返回类型。
- 构造函数在创建对象时自动被调用和执行,不能像普通的成员函数通过对象去调用。
对象的创建和销毁
- 在栈区创建单个对象
类名 对象(构造实参表); 类名 对象 = 类名(构造实参表);
- 在栈区创建多个对象(对象数组)
类名 对象数组[元素个数] = { 类名(构造实参表),类名(构造实参表),...};
- 在堆区创建/销毁单个对象
创建:类名* 对象指针 = new 类名(构造实参表); 销毁:delete 对象指针;
- 在堆区创建/销毁多个对象(对象数组)
创建: 类名* 对象指针 = new 类型[元素个数]{ 类名(构造实参表),类名(构造实参表),...}; 销毁: delete[] 对象指针;
构造函数和初始化表
- 构造函数可以重载、可以带有缺省参数
- 缺省构造函数(无参构造函数)
- 如果一个类没用定义构造函数,编译器会提供一个缺省(无参)构造函数。(对基本类型的成员变量不做初始化,对类、类型的成员变量会自动调用相应的类的无参构造函数来初始化)
- 如果自己定义了构造函数,无论是否有参数,编译器都不会再提供缺省的构造函数了。
- 类型转换构造函数(单参构造函数)
class 目标类型{ [explicit] 目标类型(源类型){...} }; 可以实现源类型到目标类型的隐式转换。 注:使用explicit关键字,可以强制这种转换必须显式的完成。
- 拷贝(复制)构造函数
- 用一个已存在的对象构造同类型的副本对象时,会调用该类的拷贝构造函数。
- 如果一个类中没用定义拷贝构造函数,那么编译器会为其提供一个缺省的拷贝构造函数。(对基本类型成员变量按字节复制;对类类型成员变量(成员子对象),自动调用相应类型的拷贝构造函数,多数情况下不需要自己写拷贝构造函数,因为编译器缺省提供的拷贝构造函数已经很好使用了。)
- 拷贝构造函数调用时机:用已存在的对象作为同类对象的构造实参;以对象的形式向函数传递参数;从函数中反悔对象(可能被编译器优化掉)
class 类名{ 类名(const 类名&){...} }; eg: class A{...}; A a1; A a2(a1);//调用拷贝构造函数
- 初始化表
- 如果有类、类型成员变量(成员子对象),而该类又没用无参构造函数,则必须使用初始化表来初始化该成员变量。
class 类名{ 类名(形参表):成员变量(初值),...{} };
代码示例
- constructor.cpp
#include <iostream> using namespace std; class Student{ public: Student(const string& name,int age, int no){ cout << "构造函数" << endl; m_name = name; m_age = age; m_no = no; } void who(void){ cout << "我叫" << m_name << ",今年" << m_age << "岁,学号是" << m_no << endl; } private: string m_name; int m_age; int m_no; }; int main(void) { //创建对象,实例化对象,构造对象 //(...),指明构造函数需要的实参 Student s("李辉",35,10011); s.who(); //构造函数不能想普通成员函数一样去调用 //s.Student("李三",36,10012); return 0; }
- 执行结果
- clock.cpp
#include <iostream> #include <cstdio> #include <ctime> #include <unistd.h> class Clock{ public: Clock(time_t t){ tm* local = localtime(&t); m_hour = local->tm_hour; m_min = local->tm_min; m_sec = local->tm_sec; } void run(void){ while(1){ printf("\r%02d:%02d:%02d", m_hour,m_min,m_sec); fflush(stdout);//刷新输出缓冲区 if(++m_sec == 60){ m_sec = 0; if(++m_min == 60){ m_min = 0; if(++m_hour == 24) m_hour = 0; } } sleep(1); } } private: int m_hour; int m_min; int m_sec; }; int main(void) { Clock c(time(0)); c.run(); return 0; }
- 执行结果
- 02constructor.cpp
#include <iostream> using namespace std; class Student{ public: Student(const string& name,int age, int no){ cout << "构造函数" << endl; m_name = name; m_age = age; m_no = no; } void who(void){ cout << "我叫" << m_name << ",今年" << m_age << "岁,学号是" << m_no << endl; } private: string m_name; int m_age; int m_no; }; int main(void) { //创建对象,实例化对象,构造对象 //(...),指明构造函数需要的实参 //Student s("李辉",35,10011); //和上面等价 Student s = Student("李辉",35,10011); s.who(); //栈区创建对象数组 Student sarr[3] = { Student("白骨精",19,10012), Student("林黛玉",18,10013), Student("潘金莲",20,10014)}; sarr[0].who(); sarr[1].who(); sarr[2].who(); //在堆区创建单个对象 Student* ps = new Student("貂蝉",17,10015); ps->who();//(*ps).who() delete ps; ps = NULL; //在堆区创建多个对象,c++11 Student* parr = new Student[3]{ Student("小乔",28,10016), Student("大乔",29,10017), Student("西施",30,10018)}; parr[0].who();//(*(parr+0)).who() parr[1].who(); parr[2].who(); delete[] parr; parr = NULL; return 0; }
- 执行结果
- defCons.cpp
#include <iostream> using namespace std; class A{ public: A(void){ cout << "A的无参构造函数" << endl; m_data = 12345; } int m_data; }; class B{ public: //B(int num){} int m_num;//基本类型 A m_a;//类 类型(成员子对象) }; int main(void) { B b; cout << b.m_num << endl;//? cout << b.m_a.m_data << endl;//12345 return 0; }
- 执行结果
- castCons.cpp
#include <iostream> using namespace std; class Integer{ public: Integer(void){ cout << "Integer(void)" << endl; m_data = 0; } //int->Integer //类型转换构造函数 /*explicit*/ Integer(int data){ cout << "Integer(int)" << endl; m_data = data; } void print(void){ cout << m_data << endl; } private: int m_data; }; int main(void) { Integer i; i.print();//0 //1)自动调用类型转换构造函数,用123作为 //构造实参创建一个临时对象 //2)再用临时对象给i进行赋值操作 i = 123; i.print();//123 //使用类型转换构造函数实现的隐式转换代码 //可读性差,推荐使用显式转换 //i = (Integer)321;//C风格 i = Integer(321);//C++风格 i.print();//321 return 0; }
- 执行结果
- cpCons.cpp
#include <iostream> using namespace std; class A{ public: A(int data = 0){ cout << "A(int=0)" << endl; m_data = data; } //拷贝构造函数 A(const A& that){ cout << "A(const A&)" << endl; m_data = that.m_data; } int m_data; }; int main(void) { const A a1(12345); A a2(a1); //A a2 = a1;//和上面写法完全等价 cout << a1.m_data << endl; cout << a2.m_data << endl; return 0; }
- 执行结果
- 02cpCons.cpp
#include <iostream> using namespace std; class A{ public: A(int data = 0){ cout << "A(int)" << endl; m_data = data; } A(const A& that){ cout << "A(const A&)" << endl; m_data = that.m_data; } int m_data; }; class B{ public: A m_a;//成员子对象 }; int main(void) { B b; b.m_a.m_data = 12345; B b2(b);//拷贝构造 cout << b.m_a.m_data << endl;//12345 cout << b2.m_a.m_data << endl;//12345 return 0; }
- 执行结果
- 03cpCons.cpp
#include <iostream> using namespace std; class A{ public: A(void){ cout << "A(void)" << endl; } A(const A& that){ cout << "A(const A&)" << endl; } }; void foo(A a){} A bar(void){ A a;//无参 cout << "&a=" << &a << endl; return a;//拷贝 } int main(void) { A a1;//无参 A a2 = a1;//拷贝 foo(a1);//拷贝 /* 正常情况bar返回a拷贝到临时对象,临时 * 对象再拷贝到a3,发生两次拷贝;但是因 * 为编译器优化,让a3直接引用a,不再发生 * 拷贝*/ //去优化的选项 //g++ xx.cpp -fno-elide-constructors A a3 = bar();//拷贝 cout << "&a3=" << &a3 << endl; return 0; }
- 执行结果
- initlist.cpp
#include <iostream> using namespace std; class Student{ public: //先把成员变量定义出来(内存分配) //再执行构函数函数体,赋初值 /*Student(const string& name,int age, int no){ cout << "构造函数" << endl; m_name = name; m_age = age; m_no = no; }*/ //使用初始化表:定义成员变量同时初始化 Student(const string& name,int age, int no):m_name(name),m_age(age), m_no(no){} void who(void){ cout << "我叫" << m_name << ",今年" << m_age << "岁,学号是" << m_no << endl; } private: string m_name; int m_age; int m_no; }; int main(void) { //创建对象,实例化对象,构造对象 //(...),指明构造函数需要的实参 Student s("李辉",35,10011); s.who(); return 0; }
- 执行结果
- 02initlist.cpp
#include <iostream> using namespace std; class A{ public: A(int data){ cout << "A的构造函数" << endl; m_data = data; } int m_data; }; class B{ public: //:m_a(..),显式指明成员子对象m_a的 //初始化方式 B(void):m_a(12345){ cout << "B的构造函数" << endl; } A m_a; }; int main(void) { B b; return 0; }
- 执行结果
企业员工类emloyee
- employee.cpp
#include <iostream> using namespace std; class Employee{ public: void printInfo(void){ cout << "姓名:" << m_name << endl; cout << "工号:" << m_id << endl; cout << "基础工资:" << m_salary << endl; } void calSalary(void){ cout << "请输入出勤天数:"; int days; cin >> days; double basic = m_salary * (days/23.0); double merit = basic / 2; cout << "总工资:" << (basic + merit) << endl; } public: void setId(int id){ if(id<10000) cout << "无效的工号" << endl; else m_id = 10011; } void setName(const string& name){ if(name.size() > 20) cout << "无效的姓名" << endl; else m_name = name; } void setSalary(double salary){ if(salary<0) cout << "无效的工资" << endl; else m_salary = salary; } private: int m_id;//工号 string m_name;//姓名 double m_salary;//工资 }; int main() { Employee emp; emp.setId(10011); emp.setName("张三"); emp.setSalary(6600); emp.printInfo(); emp.calSalary(); return 0; }
- 执行结果