标签:
类和对象
一、什么是对象
1、万物皆对象
2、程序就是一组对象,对象之间通过消息交换信息。数据代表信息。
3、怎么用计算机语言描述对象?"类"就是对对象的描述和抽象。对象就是类的具体化和实例化。
二、通过类描述对象
通过类描述对象, 具体就是从两个方面描述"静态属性"和"动态属性", 也就是"属性" 和 "行为"两个方面。
类就是从属性和行为两个方面对对象的描述。
三、面向对象程序设计(OOP)
现实世
界>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
虚拟世界
对象->抽象 --> 抽象->对象
(对现实世界中的各种存在 (用计算机语言抽象地描述对象,程序
的对象进行分析提取完成抽象) 运行就形成了虚拟世界的对象)
类是编译期的一个概念。对象是运行期的概念。
OOP是一种编程思想,是一种看待问题、解决问题的思维方式,和编程语言没有任何关系。面向过程的C语言完全可以以OOP的思维方式编程,只不过面向对象语言提供了类、继承、多态可以极大地方便OOP而已。
1、至少掌握一门OOP语言
2、精通一种面向对象的元语言,例如UML
3、研究设计模式
四、C++类基本语法
1、类的定义
class C_Student{
};
2、类的成员:成员变量--属性
3、类的成员:成员函数--行为
4、访问控制属性
(1)公有成员: public
(2)私有成员: private
(3)保护成员:protected 只有自己和自己的子类可以访问
注意:类的成员缺省访控属性为私有,而C++的结构体虽然已经允许拥有成员函数,但是结构体缺省访控属性为公有。
以下是类定义举例:
1 /* 2 * 文件名: s.h 3 * 描述:类Student的声明 4 */ 5 #ifndef _S_H 6 #define _S_H 7 #include <string> 8 using namespace std; 9 // 声明Student类 10 class Student { 11 public: 12 Student (const string& name = "", int age = 0); 13 void eat (const string& food); 14 private: 15 string m_name; 16 int m_age; 17 }; 18 #endif // _S_H
1 /* 2 * 文件名:s.cpp 3 * 描述:类Student的实现 4 * */ 5 #include <iostream> 6 using namespace std; 7 #include "s.h" 8 // 实现Student类 9 Student::Student (const string& name /* = "" */, 10 int age /* = 0 */) : m_name (name), 11 m_age (age) {} 12 void Student::eat (const string& food) { 13 cout << m_name << "," << m_age << "," << food 14 << endl; 15 }
1 /* 2 *文件名: main.cpp 3 *描述: 4 * */ 5 #include "s.h" 6 // 使用Student类 7 int main (void) { 8 Student s ("张飞", 25); 9 s.eat ("包子"); 10 return 0; 11 }
5、构造函数
构造函数没有返回类型(根本就是没有返回类型,返回类型绝对不要以为是void)。构造函数函数名称必须和类名称一样。当一个对象被创建是,构造函数会自动被执行,以完成对象的构造,构造函数参数来自构造实际参数。
构造函数定义语法:
class C_Name {
....
类名 (形式参数表){
...
}
};
6、构造函数可以通过构造参数实现重载。
7、如果一个类没有定义任何构造函数,那么编译器就会缺省地为其提供一个void参数构造函数,该构造函数对于基本类型的成员变量不做初始化,对于类类型的成员变量,是会调用其相应的类型的无参构造
8、对象的创建过程。
分配内存->调用构造函数->调用类类型成员的构造函数->构造函数代码
9、初始化表。写在构造函数名称和构造函数体之间的初始化列表。
class 类名称 {
类名称(...) : 初始化表
{
构造函数体
}
};
(1)如果类中有常量或者引用型的成员变量,必须通过初始化表对其初始化。(P.S.成员变量的定义是在构造函数构造对象的时候发生的。)
1 /* 2 *如果类中有常量或者引用型的成员变量,必须通过初始化表对其初始化。(P.S.成员变量的定义是在构造函数构造对象的时候发生的。) 3 * */ 4 #include <iostream> 5 using namespace std; 6 int g_data = 1000; 7 class A { 8 public: 9 A (void) : m_c (100), m_r (g_data) { 10 //m_c = 100;//ERROR 11 //m_r = g_data;//ERROR 12 } 13 void print (void) { 14 cout << m_c << ‘ ‘ << m_r << endl; 15 } 16 private: 17 const int m_c; 18 int& m_r; 19 }; 20 int main (void) { 21 A a; 22 a.print (); 23 return 0; 24 }
(2)成员变量的初始化顺序仅与其被声明的顺序有关,而于初始化表的顺序无关。成员变量之间应该尽可能减少相互依赖(p.s这叫做耦合),因为初始化顺序很可能影响相互依赖的成员。
(post script:注意严格区别"初始化语句"和"赋值语句"
int a = 0;//初始化语句,"="为初始化操作符
int b ;
b = 0;//赋值语句,"="为赋值操作符
)
10、类定义语法分为声明部分和实现部分。我们往往将类的声明和实现分开书写。
声明部分:class C_Name {/*这里面的都应该是声明语句。包括成员对象(简单对象,复杂对象),成员函数。*/};
五、this指针
(p.s.this指针不是类的成员变量。this是成员函数缺省的形式参数)
1、一般而言,在类的构造函数或者成员函数中,关键字this表示一个指针,对于构造函数而言,this指向正在被构造的对象,对于成员函数而言,this指向调用该函数的对象。
2、this指针的用途
(1)在类的内部,可以用this对成员变量加以区分。
(2) 在成员函数中返回调用对象自身。
(3) 在成员函数内部通过参数向外界传递调用对象自身,以实现对象间交互。
老 -问题-> 学
师 <-答案- 生
1 /* 2 * this指针举例 3 * 4 *老 -问题-> 学 5 <p> *师 <-答案- 生</p> * 6 */ 7 #include <iostream> 8 using namespace std; 9 class Student; 10 class Teacher { 11 public: 12 void educate (Student* s); 13 void reply (const string& answer) { 14 m_answer = answer; 15 } 16 private: 17 string m_answer; 18 }; 19 class Student { 20 public: 21 void ask (const string& question, Teacher* t) { 22 cout << "问题:" << question << endl; 23 t->reply ("不知道。"); 24 } 25 }; 26 void Teacher::educate (Student* s) { 27 s->ask ("什么是this指针?", this); 28 cout << "答案:" << m_answer << endl; 29 } 30 int main (void) { 31 Teacher t; 32 Student s; 33 t.educate (&s); 34 return 0; 35 }
C++不允许如下交叉类:
class A {
B m_b;
};
class B {
A m_a;
};
sizeof (A) ?
class C {
C m_c;
};
但是可以有这样的交叉:
class B;
class A{
B & m_b;//或者B * m_b;
};
class B{
A & m_a;//或者A * m_a;
};
class C{
C *m_c;//或者C& m_c;
};
六、常函数与常对象
1.如果在一个类的成员函数的参数表后面加上const关键字,那么这个成员函数就被称为常函数,常函数的this指针是一个常指针。在常函数内部无法修改成员变量,除非该变量具有mutable属性。而且在常函数内部也无法调用非常函数。
2.常对象:拥有const属性的对象,对象引用或指针。
常对象只能调用常函数。
同型的常函数和非常函数可以构成重载关系(因为他们的形式参数确实不一样,一个是常指针this, 一个是普通指针this)。常对象调用常版本,非常对象调用非常版本。如果没有非常版本,非常对象也可以调用常版本。
1 /* 2 *常函数与常对象 3 * */ 4 #include <iostream> 5 using namespace std; 6 class A { 7 public: 8 // void bar (void) { 9 // cout << "非常bar" << endl; 10 // } 11 void bar (void) const { 12 cout << "常bar" << endl; 13 } 14 // void XXXbarYYY (A* this) {} 15 void foo (void) const { 16 // m_i = 100; 17 const_cast<A*>(this)->m_i = 100; 18 } 19 void print (void) const {//const关键字是用来修饰缺省形式参数this的,也就是说本函数的this指针是常指针。 20 cout << m_i << endl; 21 } 22 // _ZNK1A3fooEv (const A* this) { 23 // const_cast<A*>(this)->m_i = 100; 24 // } 25 int m_i;//mutable int m_i;//加上mutable修饰符后,常函数就可以修改成员变量m_i了。 26 }; 27 void func (void) /*const*/ {} 28 int main (void) { 29 A a; 30 a.foo (); 31 a.print (); 32 const A& r = a; 33 r.bar (); 34 // XXXbarYYY (&r); // const A* 35 a.bar (); 36 // XXXbarYYY (&a); // A* 37 return 0; 38 }
理解下面三个const修饰符修饰的是谁?
const XXX 函数名 (const YYY yyy) const {//第一个const修饰返回类型
//中间的const修饰形式参数类型
... //最后一个const修饰成员函数的缺省形式参数this.
}
七、析构函数
class 类名 {
~类名 (void) {//析构函数参数必须是void型,函数名称必须是~类名称
析构函数体;
}
};
当一个对象被销毁时自动执行析构函数。
局部对象离开作用域时被销毁,堆对象被delete时被销毁。
如果一个类没有定义任何析构函数,那么系统会提供一个缺省析构函数。缺省析构函数对基本类型的成员变量什么也不干,对类类型的成员变量,调用相应类型的析构函数。
一般情况下,在析构函数中释放各种动态分配的资源。
构造:基类->成员->子类
析构:子类->成员->基类
标签:
原文地址:http://www.cnblogs.com/libig/p/4741162.html