5、构造函数
构造函数没有返回类型(根本就是没有返回类型,返回类型绝对不要以为是void)。构造函数函数名称必须和类名称一样。当一个对象被创建是,构造函数会自动被执行,以完成对象的构造,构造函数参数来自构造实际参数。
构造函数定义语法:
class C_Name {
....
类名 (形式参数表){
...
}
};
6、构造函数可以通过构造参数实现重载。
7、如果一个类没有定义任何构造函数,那么编译器就会缺省地为其提供一个void参数构造函数,该构造函数对于基本类型的成员变量不做初始化,对于类类型的成员变量,是会调用其相应的类型的无参构造
8、对象的创建过程。
分配内存->调用构造函数->调用类类型成员的构造函数->构造函数代码
9、初始化表。写在构造函数名称和构造函数体之间的初始化列表。
class 类名称 {
类名称(...) : 初始化表
{
构造函数体
}
};
(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) 在成员函数内部通过参数向外界传递调用对象自身,以实现对象间交互。
老 -问题-> 学
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)。常对象调用常版本,非常对象调用非常版本。如果没有非常版本,非常对象也可以调用常版本。
理解下面三个const修饰符修饰的是谁?
const XXX 函数名 (const YYY yyy) const {//第一个const修饰返回类型
//中间的const修饰形式参数类型
... //最后一个const修饰成员函数的缺省形式参数this.
}
七、析构函数
class 类名 {
~类名 (void) {//析构函数参数必须是void型,函数名称必须是~类名称
析构函数体;
}
};
当一个对象被销毁时自动执行析构函数。
局部对象离开作用域时被销毁,堆对象被delete时被销毁。
如果一个类没有定义任何析构函数,那么系统会提供一个缺省析构函数。缺省析构函数对基本类型的成员变量什么也不干,对类类型的成员变量,调用相应类型的析构函数。
一般情况下,在析构函数中释放各种动态分配的资源。
构造:基类->成员->子类
析构:子类->成员->基类
构造函数没有返回类型(根本就是没有返回类型,返回类型绝对不要以为是void)。构造函数函数名称必须和类名称一样。当一个对象被创建是,构造函数会自动被执行,以完成对象的构造,构造函数参数来自构造实际参数。
构造函数定义语法:
class C_Name {
....
类名 (形式参数表){
...
}
};
6、构造函数可以通过构造参数实现重载。
7、如果一个类没有定义任何构造函数,那么编译器就会缺省地为其提供一个void参数构造函数,该构造函数对于基本类型的成员变量不做初始化,对于类类型的成员变量,是会调用其相应的类型的无参构造
8、对象的创建过程。
分配内存->调用构造函数->调用类类型成员的构造函数->构造函数代码
9、初始化表。写在构造函数名称和构造函数体之间的初始化列表。
class 类名称 {
类名称(...) : 初始化表
{
构造函数体
}
};
(1)如果类中有常量或者引用型的成员变量,必须通过初始化表对其初始化。(P.S.成员变量的定义是在构造函数构造对象的时候发生的。)
/*
*如果类中有常量或者引用型的成员变量,必须通过初始化表对其初始化。(P.S.成员变量的定义是在构造函数构造对象的时候发生的。)
* */
#include <iostream>
using namespace std;
int g_data = 1000;
class A {
public:
A (void) : m_c (100), m_r (g_data) {
//m_c = 100;//ERROR
//m_r = g_data;//ERROR
}
void print (void) {
cout << m_c << ' ' << m_r << endl;
}
private:
const int m_c;
int& m_r;
};
int main (void) {
A a;
a.print ();
return 0;
}
(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) 在成员函数内部通过参数向外界传递调用对象自身,以实现对象间交互。
老 -问题-> 学
师 <-答案- 生
/*
* this指针举例
*
*老 -问题-> 学
<p> *师 <-答案- 生</p> *
*/
#include <iostream>
using namespace std;
class Student;
class Teacher {
public:
void educate (Student* s);
void reply (const string& answer) {
m_answer = answer;
}
private:
string m_answer;
};
class Student {
public:
void ask (const string& question, Teacher* t) {
cout << "问题:" << question << endl;
t->reply ("不知道。");
}
};
void Teacher::educate (Student* s) {
s->ask ("什么是this指针?", this);
cout << "答案:" << m_answer << endl;
}
int main (void) {
Teacher t;
Student s;
t.educate (&s);
return 0;
}
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)。常对象调用常版本,非常对象调用非常版本。如果没有非常版本,非常对象也可以调用常版本。
/*
*常函数与常对象
* */
#include <iostream>
using namespace std;
class A {
public:
// void bar (void) {
// cout << "非常bar" << endl;
// }
void bar (void) const {
cout << "常bar" << endl;
}
// void XXXbarYYY (A* this) {}
void foo (void) const {
// m_i = 100;
const_cast<A*>(this)->m_i = 100;
}
void print (void) const {//const关键字是用来修饰缺省形式参数this的,也就是说本函数的this指针是常指针。
cout << m_i << endl;
}
// _ZNK1A3fooEv (const A* this) {
// const_cast<A*>(this)->m_i = 100;
// }
int m_i;//mutable int m_i;//加上mutable修饰符后,常函数就可以修改成员变量m_i了。
};
void func (void) /*const*/ {}
int main (void) {
A a;
a.foo ();
a.print ();
const A& r = a;
r.bar ();
// XXXbarYYY (&r); // const A*
a.bar ();
// XXXbarYYY (&a); // A*
return 0;
}
理解下面三个const修饰符修饰的是谁?
const XXX 函数名 (const YYY yyy) const {//第一个const修饰返回类型
//中间的const修饰形式参数类型
... //最后一个const修饰成员函数的缺省形式参数this.
}
七、析构函数
class 类名 {
~类名 (void) {//析构函数参数必须是void型,函数名称必须是~类名称
析构函数体;
}
};
当一个对象被销毁时自动执行析构函数。
局部对象离开作用域时被销毁,堆对象被delete时被销毁。
如果一个类没有定义任何析构函数,那么系统会提供一个缺省析构函数。缺省析构函数对基本类型的成员变量什么也不干,对类类型的成员变量,调用相应类型的析构函数。
一般情况下,在析构函数中释放各种动态分配的资源。
构造:基类->成员->子类
析构:子类->成员->基类