函数
<局部对象>
在C++语言中,每个名字都有作用域,而每个对象都有生命期。名字的作用域指的是知道该名字的程序文本区。对象的生命期则是程序执行过程中对象存在的时间。
<<自动对象>>
自动变量(对象):只有定义它的函数被调用是才存在的对象成为自动对象。
void fun(int arg)
{
// arg 自动对象(变量)
auto int num; // 自动变量(对象)
}
函数被调用,则自动对象将在栈中分配局部存储空间
函数调用结束,则自动对象就会被收回局部内存空间
<<静态局部变量>>
在定义变量时,使用static关键字即可将该变量定义为静态局部变量。
静态局部变量,一旦被创建并初始化为0,直到程序结束该对象才会被撤销并收回存储空间。
size_t count_calls()
{
static size_t ctr; // 自动初始化为零值..value will persit across calls
return ++ctr;
}
int main()
{
for (size_t i = 0; i != 10; ++i)
{
cout << count_calls() << end;
}
return 0;
}
<内联函数>
在定义函数的时候,在返回类型前加上关键字inline即可将函数定义为内联函数。
普通函数调用:
调用函数都要做很多工作:调用前要先保存寄存器,并在返回时恢复;复制实参;程序还必须转向一个新位置执行。
内联函数:则可以避免函数调用的开销。定义为内联函数,在程序中每一次调用点上都会”内敛地”展开。
inline shorterString(const string &s1,const string&s2)
{s1.size() < s2.size() ? s1 : s2}
调用时
cout << shorterString() << endl;
编译时将内联展开为:
cout << (si.size() < s2.size() ? s1 : s2) << endl;
内联函数应该放入头文件中定义,它的定义对编译器而言必须是可见的,以便编译器能够在调用点内敛展开该函数的代码。
在头文件中加入或修改内联函数是,使用了该头文件的所有源文件都必须重新编译。
<成员函数>
包含四部分:
函数返回类型、函数名、用逗号隔开的形参表(可为void)、包含在一对花括号里面的函数体。
函数原型提供了函数返回值的类型、函数的名字、传递实参的类型。函数体既可以在类中定义亦可以在类外定义。
扩展的类定义:
class Sales_item{
public:
// operation on Sales_item objects
double avg_price() const;
bool same_isbn(const Sales_item &rhs) const
{ return isbn == rhs.isbn}
private:
std::string isbn;
unsigned uints_sold;
double revenue;
};
定义成员函数的函数体
类的成员函数既可以在类的定义内定义也可以在类的定义外定义。编译器隐式地将在类内定义的成员函数当作内联函数。类的成员函数可以访问该类的private成员。
1.成员函数含有额外的、隐含的形参.
- 调用成员函数,实际上是通过使用对象来调用
if(total.same_isbn(trans))
成员函数的额外的、隐含的形参将该成员函数与调用该函数的对象捆绑在一起。这个额外的、隐含的形参就是this指针。
2.this指针的引入
- 每个成员函数(除了static成员函数为)都有一个额外的、隐含的形参this指针。调用成员函数时,该形参将初始化为调用成员函数对象的地址。
total.same_isbn(trans);
则编译器将重写该函数如下:
Sales_item::same_isbn(&total,trans);
在此调用中,same_isbn成员函数中无前缀的isbn属于total对象。
3.const成员函数
- 跟在成员函数形参表后面的const的作用:const改变了隐含this形参的类型,在调用total.same_isbn(trans)时,使之成为指向const
Sales_item *类型的指针。
//This code is illegal:We may not explicitly define the this pointer.
//Note that this is a pointer to const because same_isbn is a const member.
bool Sales_item::same_isbn(const Sales_item *const this,const Sales_item &rhs){
return (this->isbn == rhs.isbn);
}
该函数成为常量成员函数。
常量成员函数仅可以读取调用对象的数据成员,不可以修改对象的数据成员。
类似于
const int a = 2;
const int *p = &a; //const普通对象要求指向他们的指针、引用具有const属性
const对象、指向const对象的指针或引用只能用于调用其const成员函数,若尝试调用它们来调用的非const成员函数,则是错误的。
4.this指针的使用
- this指针是隐式定义的,在成员函数中可以显示地使用this指针,但却不可以显示地define this 指针,实际上显示定义this指针也是非法。
bool same_isbn(const Sales_item &rhs) const{
return (this->isbn == rhs.isbn);
}
<< 类外定义成员函数 >>
- 在类外定义成员函数需在函数返回类型与函数名之间使用类型名+作用域操作符(::)表明是该类的成员函数
type class_name::function_name(type args) const{
/*your code*/
}
形参表后面的const则反映了在类class_name中声明成员函数的形式。在任何函数定义中,返回类型和形参表必须和函数声明保持一致。对于成员函数同样适用。若函数被声明为const成员函数,则函数定义是形参表后面也必须有const。
<<类的构造函数>>
特殊的成员函数—构造函数
构造函数不同于普通成员函数,构造函数无返回值类型且与类同名,当创建类对象时,它被用于初始化类对象的数据成员。初始化式来源于构造函数形参表中的初始化式。构造函数通常应确保其每个数据成员都完成初始化。
string str; /*default constructor:empty string*/
vector<int> ivec;/*default constructor:empty vector*/
vector的默认构造函数则生成一个没有元素的vector向量对象,当然也就不能通过下标对该对象进行赋值以及读取数据。
string 对象为类类型对象,将通过类类型提供的默认构造函数初始化为”\0”
- 定义构造函数
通常构造函数作为类的接口一部分。构造函数放在pulic部分,放入private中,则使该类没有太大的作用。它的定义可以放在类内定义,也可在类外定义,但是需要类名+作用域操作符(::)放在构造函数的名称前面指明该构造函数是该类的成员函数。
在类中定义它:
class Sales_item{
public:
//operations on Sales_item objects
double avg_price()const;
bool same_isbn(const Sales_item &rhs) const
{ return (isbn == rhs.isbn) };
// default constuctor needed to initialize members of built-in type
Sales_item():units_sold(0),revenue(0.0){}
//private member as before
private:
std::string isbn;
unsigned units_sold;
double revenue;
};
构造函数的初始化列表
在冒号和花括号之间的代码称为构造函数的初始化列表。它的初始化列表为类中的各个数据成员指定初值。基本数据类型,需显示地放在初始化列表中,类类型则可以不需要,可以由该对象所属的类的默认构造函数进行该对象的初始化。
合成的构造函数
由编译器创建的默认构造函数则称为合成的构造函数,其将依据变量初始化的规则初始化类中的所有成员。变量初始化规则:
1.在全局作用域中定义一个对象,则自动初始化为0
2.使用static关键字定义一个静态局部对象,则自动初始化为0
3.定义一个类类型对象,则该对象的初始化由该对象所属的类 提供的默认构造函数去完成。合成的默认构造函数一般适用于仅包含类类型成员的类,对于含有内置类型的数据成员,则需要我们显示地提供默认构造函数以及数据成员的初始化列表。
类代码文件的组织
类定义放入单独的头文件中,类名作为头文件的文件名,类中函数的定义也单独放入一个文件中,与类名同名
Sales_item.h和Sales_item.cc。定义函数的文件中必须包含声明这个函数的头文件。