C++ 类----- 一种数据类型
-------class
属性:--------类 内部的数据
行为:--------类 内部的函数
类的变量 ------对象
类(种类) ------对象
描述事物(学生) 具体的事物(吴尚奇) 如:
1 //cat.cc 2 #include<string.h> 3 4 #include<iostream> 5 using namespace std; 6 7 //猫类 8 class Cat 9 { 10 //属性 11 char m_name[20]; //名子 //m->member成员 12 13 public://访问修饰符, - 控制类 内部成员的访问权限 14 15 //行为 16 //取名子 17 void Setname(const char *name) 18 { 19 strcpy(m_name,name); 20 return; 21 } 22 //吃食物 23 void eat() 24 { 25 cout<<m_name<<" 吃鱼 "<<endl; 26 } 27 }; 28 29 int main(int argc,char **argv) 30 { 31 Cat cat;//创建了一个cat对象 32 cat.Setname("Jinshan"); 33 cat.eat(); 34 35 return 0; 36 }
2.访问修饰符, - 控制类 内部成员的访问权限
作用是:限制类 内部成员(数据和函数)的访问(调用)
public:共有的访问修饰符
让成员在任何地方使用
Struct 的默认访问权限是public
Class 的默认访问权限是 private
protected: 受保护的访问修饰符
private:私有的访问修饰符
Protected、private只能在类的内部使用
Class A{ |<--------类的内部------->| };
通过访问修饰符 将 类 内部的重要数据进行隐藏
类的性质:
隐藏:通过访问修饰符 将 类 内部的重要数据进行隐藏
封装:将数据和函数绑定成一个逻辑单元
私有成员的访问:
一般使用共有的函数进行访问
Set()/Get()人为定义的
1 //process.cc 2 #include<iostream> 3 using namespace std; 4 5 class Test 6 { 7 public: 8 int m_a1; //若上面没有public则默认m_a1是private修饰 9 protected: 10 int m_a2; 11 private: 12 int m_a3; 13 14 public: 15 void value(int a1, int a2, int a3) 16 { 17 m_a1=a1; 18 m_a2=a2; 19 m_a3=a3; 20 } 21 void show() //m_a2和m_a3只能在类 的内部访问,在主函数里面是访问不到的 22 { 23 cout<<" m_a2="<<m_a2<<" m_a3="<<m_a3<<endl; 24 return; 25 } 26 }; 27 28 int main() 29 { 30 Test t1; 31 t1.value(2,3,4); 32 33 cout<<" m_a1="<<t1.m_a1<<endl; 34 cout<<"**********************"<<endl; 35 t1.show(); 36 37 return 0; 38 }
私有成员的访问:
一般使用共有的函数进行访问
set()/get() 人为定义的
1 //Set_get.cc 2 #include<string.h> 3 4 #include<iostream> 5 using namespace std; 6 7 class Gir1 8 { 9 char m_name[20]; //默认是private的 10 public: 11 //设置 m_name的值 12 void Setname(const char *name ) 13 { 14 strcpy(m_name,name); 15 return; 16 } 17 18 //获得m_name 的 值 19 char *Getname() 20 { 21 return m_name; 22 } 23 }; 24 25 int main(int argc, char **argv) 26 { 27 //这里的Setname()和Getname()是人为规定的对类内部私有数据访问的合法途径 28 Gir1 g1; 29 g1.Setname("颜栏栏"); 30 31 cout<<"女孩子的名子是 "<<g1.Getname()<<endl; 32 33 return 0; 34 }
作业:struct和class的区别:
解答:
class是引用类型,struct是值类型;
class可以继承类、接口和被继承,struct只能继承接口,不能被继承;
class有默认的无参构造函数,有析构函数,struct没有默认的无参构造函数,且只能声明有参的构造函数,没有析构函数;
class可以使用abstract和sealed,有protected修饰符,struct不可以用abstract和sealed,没有protected修饰符;
class必须使用new初始化,结构可以不用new初始化;
class实例由垃圾回收机制来保证内存的回收处理,而struct变量使用完后立即自动解除内存分配;
从职能观点来看,class表现为行为,而struct常用于存储数据;
作为参数传递时,class变量以按址方式传递,而struct变量是以按值方式传递的。
如何选择使用结构还是类:
1).堆栈的空间有限,对于大量的逻辑的对象,创建类要比创建结构好一些
2).结构表示如点、矩形和颜色这样的轻量对象,例如,如果声明一个含有 1000 个点对象的数组,则将为引用每个对象分配附加的内存。在此情况下,结构的成本较低
3).在表现抽象和多级别的对象层次时,类是最好的选择
4)大多数情况下该类型只是一些数据时,结构是最佳的选择。
-
构造函数和析构函数
类里面的成员函数
没有的时候,系统默认提供
构造函数:初始化类的成员数据 constructor
析构函数:释放内存空间
析构函数在一定意义上可以看作是构造函数的逆操作
1 //coustructor.cc 2 #include<iostream> 3 using namespace std; 4 5 class A 6 { 7 //构造函数 8 //1、没有返回值 9 //2、函数名就是类名 10 //3、在创建一个对象的时候,会自动调用 11 int m_i; 12 double m_d; 13 public: 14 //允许重载函数/可以带参数 15 //功能: 16 // (1)给成员数据分配内存空间 17 // (2)初始化成员数据 18 A() 19 { 20 cout<<" wushangqi"<<endl; 21 } 22 23 //可以带参数的 24 A(int i, double d) 25 { 26 m_i=i; 27 m_d=d; 28 cout<<" A() "<<endl; 29 } 30 31 void show() 32 { 33 cout<<" m_i= "<<m_i<<endl; 34 cout<<" m_d= "<<m_d<<endl; 35 } 36 }; //don't forget me -> ; 37 38 int main(int argc, char **argv) 39 { 40 //通过参数列表将实参传给构造函数的形参 41 A a(10,3.14);//创建了一个对象a 根据函数的参数自动匹配 42 a.show(); 43 return 0; 44 }
析构函数:
1 //disconstructor.cc 2 #include<iostream> 3 using namespace std; 4 5 class A 6 { 7 //析构函数 8 //1、没有返回值 9 //2、函数名和类名相同 10 //3、用 ~ 修饰函数 11 //4、不带参数的 12 public: 13 //在对象消亡的时候,会自动调用 14 ~A() 15 { 16 cout<<" ~A() "<<endl; 17 } 18 19 }; 20 21 int main(int argc, char **argv) 22 { 23 A a; 24 cout<<"~~~~~~~~~~~~~飘过~~~~~~~~~~~"<<endl; 25 26 return 0;//在函数结束的时候消亡,这个时候自动调用析构函数 27 }
作业2:
析构函数和构造函数可以手动调用吗?(重要)
解答:
构造函数是不能手动调用的。
析构函数可以手动调用。逻辑上是错误的。
C++中, 构造函数和析构函数可以被显示调用. 显示调用默认构造函数的语法: a.A::A();(不能写成a.A();) , 显示调用非默认构造函数的语法: a.A::A(7);(不能写成a.A(7);); 显示调用析构函数的语法: a.A::~A();(可以写成a.~A();) .
显示调用构造函数和析构函数就像调用一般的函数一样, 并不意味着创建或销毁对象;
如果构造函数中动态分配了空间, 则显示调用构造函数会造成内存泄露. 创建对象时的隐式构造函数调用已经为对象分配了动态内存. 当用创建好的对象显示调用构造函数时, 对象指向的动态内存更新显示调用时所分配的, 对象生命周期结束时析构函数所释放掉的是后一次分配的动态内存, 也就是说创建对象时隐式构造函数调用所分配的那块内存泄漏了.
如果析构函数中释放动态分配的空间, 则会造成多次释放同一内存, 会出现严重错误.
隐含成员
当一个类没有写 构造函数 和 析构函数 的时候 系统会自动提供构造函数和析构函数,一旦程序写了构造函数和析构函数,系统就不会再提供默认的 构造函数和 析构函数
构造函数 和 手写函数即使不作任何操作,仍然需要手写,为了 提高调用的速度
类的隐藏成员
构造函数 和 析构函数
this指针,指向对象的地址
1 //this.cc 2 #include<iostream> 3 using namespace std; 4 5 class A 6 { 7 public: 8 void Addr() 9 { 10 //this 当前对象的地址 11 cout<<" this = "<<this<<endl; 12 } 13 }; 14 15 int main(int argc, char **argv) 16 { 17 A a1; 18 A a2; 19 20 cout<<endl; 21 cout<<" 打印a1的地址:"<<endl; 22 cout<<" &a1 = "<<&a1<<endl; 23 a1.Addr(); 24 25 cout<<"---------------------------"<<endl; 26 27 cout<<" 打印a2的地址:"<<endl; 28 cout<<" &a2 = "<<&a2<<endl; 29 a2.Addr(); 30 31 return 0; 32 }
1 /*练习1: 2 设计一个分数类: 3 一个分数包含分子和分母 4 (1)设置分数的值 5 (2)可以按格式打印 6 12,13 12/13 7 (3)可以约分(注意+/-符号的处理) 8 12,-16 -3/4 9 */ 10 //Fract.cc 11 #include <iostream> 12 using namespace std; 13 14 /** 15 * Fraction 16 **/ 17 class Fract 18 { 19 int m_n; // 分子 20 int m_d; // 分母 21 public: 22 Fract(int n,int d); 23 ~Fract(){} 24 25 void print(); // 打印分数 26 void reduc(); // 约分 27 }; 28 29 Fract::Fract(int n,int d) 30 { 31 m_n = n; 32 m_d = d; 33 } 34 35 // 打印分数 36 void Fract::print() 37 { 38 cout << m_n << "/" << m_d << endl; 39 return ; 40 } 41 42 // 约分 43 void Fract::reduc() 44 { 45 // 处理+/-符号问题 46 if( m_d < 0) 47 { 48 m_d = -m_d; 49 m_n = -m_n; 50 } 51 52 // 找最大公约数 53 int i; 54 for(i = m_d; i > 1 ; --i) 55 { 56 if( (m_n%i == 0) && (m_d%i == 0)) 57 { 58 m_n /= i; 59 m_d /= i; 60 break; 61 } 62 } 63 64 return ; 65 } 66 67 68 int main(int argc,char **argv) 69 { 70 Fract f(-12,16); 71 f.reduc(); 72 f.print(); // -3/4 73 return 0; 74 }
1 /*练习2: 2 设计一个日期类 3 日期包含 年/月/日 4 (1)可以设置日期 5 (2)判断闰年 6 (3)输出 当前日期 是 该年的第几天 7 2014/4/26 -> 2014年的第?天 8 */ 9 //Data.cc 10 #include <iostream> 11 using namespace std; 12 13 static int arrday[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; 14 15 /** 16 * 日期类 17 */ 18 class Date 19 { 20 int m_year; // 年 21 int m_month; // 月 22 int m_day; // 日 23 public: 24 Date(int year,int month,int day); 25 ~Date(){} 26 27 // 获得年份 28 int GetYear(){ return m_year;} 29 30 void show(); // 显示日期 31 bool isLeapYear(); // 判断是否为闰年 32 int DayofYear(); // 今年的第几天 33 34 }; 35 36 Date::Date(int year,int month,int day) 37 { 38 m_year = year; 39 m_month = month; 40 m_day = day; 41 } 42 43 // 1.显示日期 44 void Date::show() 45 { 46 cout << m_year << "/" 47 << m_month << "/" 48 << m_day << endl; 49 return ; 50 } 51 52 // 2.判断是否为闰年 53 bool Date::isLeapYear() 54 { 55 return ( (m_year%4 == 0) && (m_year%100 != 0) ) || (m_year%400 == 0); 56 } 57 58 // 2014/4/26 59 // 计算前3个月的天数 + m_day 60 61 // 3.今年的第几天 62 int Date::DayofYear() 63 { 64 int sum = 0; 65 66 //1.计算m_month之前几个月的天数之和 67 int i; 68 for(i=0; i< m_month - 1; ++i) 69 { 70 sum += arrday[i]; 71 } 72 73 //2.加上m_month本月的天数 74 sum += m_day; 75 76 //3.二月问题处理 77 if( m_month > 2) 78 sum += isLeapYear(); 79 80 return sum; 81 } 82 83 int main(int argc,char **argv) 84 { 85 Date d(2000,4,26); 86 d.show(); 87 88 cout << d.GetYear() << " 是闰年吗? " 89 << (d.isLeapYear()?"是":"不是") 90 << endl; 91 92 cout << "是今年的第 " 93 << d.DayofYear() 94 << " 天" << endl; 95 96 return 0; 97 }
1、局部对象的构造和析构的顺序
最先构造的对象,最后析构
数据存放栈区,先进后出
全局对象/局部对象/静态对象
Class A{};
A a1;//全局
Void fn()
{
A a3;
Static A a4;
}
Int main()
{
A a2;
Fn();
A a5;
Return 0;
}
请问这些对象的构造和析构顺序????????????
-
C++是如何操作堆空间的
C语言 malloc() free()
C++语言 new delete 运算符
1 //memory.cc 2 3 #include<iostream> 4 5 using namespace std; 6 7 int main(int argc, char **argv) 8 9 { 10 11 //这里的new和delete是运算符,不是函数 12 13 int *pi= new int ;//申请堆空间 14 15 *pi = 10; 16 17 cout<<" *pi="<<*pi<<endl; 18 19 delete pi;//释放堆空间 20 21 return 0; 22 23 }
作业:
Malloc/free与new/delete的区别
从面向对象来说,new/delete和malloc/free的区别是:malloc/free只是单纯的进行内存空间的分配和释放,而使用new/delete时,不仅分配了内存空间,若new/delete的是一个类,还会调用类(经测试,基本类型好像不会进行默认初始化)的构造函数或析构函数。
简单来说,两者的区别主要有:
1. malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符,与"+“、”-“、”*“、”/“有一样的地位。
2. new/delete是可以重载的,而重载之后,就成为了函数。
3. malloc在申请内存的时候,必须要提供申请的长度,而且返回的指针是void*型,必须要强转成需要的类型。
4. 当new/delete在类中被重载的时候,可以自定义申请过程,比如记录所申请内存的总长度,以及跟踪每个对象的指针。
5. new/delete,其实内部也调用了malloc/free。
两者的共同点有:
1. 都必须配对使用,防止内存泄露。
2. 都可用于申请动态内存和释放内存,都是在堆中分配内存。
3. free和delete可以释放NULL指针。
注意点:
不建议将new/delete与malloc/free混合使用:将new和delete或malloc和free混合使用並不是好主意。當你企圖對著一个「因new而得的指標」呼叫free時,或是對著一個「因malloc而得的指標」呼叫delete時,其結果都未有定義。而我們都知道所謂「未有定義」的意思就是:它在開發階段沒問題,它在測試階段沒問題,但是它會在你最重要的客戶面前突然爆發。
-
初始化列表
功能:初始化类的成员数据
1 //init_list.cc 2 3 #include<iostream> 4 5 using namespace std; 6 7 class A 8 9 { 10 11 int m_data; 12 13 int m_data2; 14 15 public: 16 17 A(int data,int data2):m_data(data),m_data2(data2)//使用初始化列表初始化成员数据 18 19 { 20 21 //使用初始化列表的时候,初始化成员变量并赋值 22 23 //调用构造函数的时候 24 25 26 27 //m_data=data; m_data2=data2; 28 29 //调用构造函数的时候 30 31 //第一步:定义成员数据(分配空间) 32 33 //第二布:执行构造函数体内的语句 34 35 cout<<m_data<<endl; 36 37 cout<<m_data2<<endl; 38 39 } 40 41 ~A() 42 43 { 44 45 46 47 } 48 49 }; 50 51 int main(int argc,char **argv) 52 53 { 54 55 A a(10,13); 56 57 return 0; 58 59 }
-
拷贝构造函数(重新整理)
调用:用一个对象初始化另外一个对象的时候
1 //copy_construct.cc 2 3 #include<iostream> 4 5 using namespace std; 6 7 class A 8 9 { 10 11 int m_data; 12 13 public: 14 15 A(int data):m_data(data) 16 17 { 18 19 cout<<"A()"<<endl; 20 21 } 22 23 ~A() 24 25 { 26 27 cout<<"~A()"<<endl; 28 29 } 30 31 void show() 32 33 { 34 35 cout<<" m_data = "<<m_data<<endl; 36 37 return; 38 39 } 40 41 }; 42 43 int main() 44 45 { 46 47 A a1(10); 48 49 //用a1初始化a2 50 51 A a2(a1); 52 53 a2.show(); 54 55 A a3=a1;//用a1初始化a3 56 57 a3.show(); 58 59 return 0; 60 61 }
浅拷贝----带用系统默认的拷贝构造函数 只拷贝数据的值
危害:在有指针变量的时候,它只能拷贝一个地址,一旦其中的某个对象将申请的空间释放,其他对象的指针成员都没有值了。一般只允许在不进行内存空间的情况下可用。
深拷贝----调用自己写的拷贝函数
在有指针成员变量的时候,直接在拷贝构造函数中为改指针成员申请空间
String 类----处理字符串的
--by 吴尚奇 Dervil_box 2014/05