定义一个类:
class Myclass{ int data_i; string data_str; public: int getdata_i() const { return data_i; } string getdata_str() const {return data_str; } }; // 不要忘了分号!
我们用关键字class定义了一个C++类,我们也可以用struct来定义,两者的区别在于:用struct定义的类,在第一个访问控制说明符之前的类成员默认为public的,而class定义的类默认为private的。
因此,data_i和data_str就是private的。getdata_i()和getdata_str()分别获得两个成员的值,因为private的值可以由成员函数来访问,在成员函数中,隐式的传进去了一个参数this指针,这个指针的地址是类的地址。this指针类型为:Myclass *const ,所以,我们也可以显示的写出来:
int getdata_i() const { return this->data_i; }
理论上,这两个函数并不会改变成员的值,因此我们可以将这两个函数定义为常量成员函数。 即就是在成员函数参数列表和函数体之间添加const关键字。
const用来修饰this的类型,添加了const会将this指针转变为具有底层cosnt的性质:const Myclass* const this。指向常量的指针不会修改对象的值,因此我们就是实现了不改变类成员的值的效果。常量对象,以及常量的引用和指针都只能调用常量成员函数
定义在类内部的成员函数默认为inline内联的,我们也可以指定定义在类外部的成员函数为内联函数:
我们为这个类新添加一个成员函数,并将其定义为inline的:
// 声明 inline void showdata() const; // 定义 inline void Myclass::showdata() const { cout << data_i << ' ' << data_str; }
类的构造函数:
我们没有为这个类定义任何的构造函数,那么编译器负责会为我们定义一个默认构造函数,也叫合成的默认构造函数。
并不是所有的类都能依赖合成的默认构造函数,原因有三:
1. 我们在类中定义了其他的构造函数,因为编译器只有在我们没有定义任何构造函数时才会为我们定义一个默认构造函数。除非我们再定义一个默认的构造函数,否则我们没有默认构造函数。
2. 如果我们的类中有内置类型成员或复合成员类型,只有这些成员都被赋予了类内初始值时,这个类才适合使用合成的默认构造函数。
3. 如果类中包含另一个类类型的成员,而且这个类没有默认构造函数,那么编译器无法初始化这个成员。
在C++11中,我们可以使用 =default 来要求编译器生成默认构造函数。
在构造函数初始值列表中,初始化顺序和它们出现的顺序一致。
如果一个构造函数为所有的参数都提供了默认实参,实际上它就是个默认构造函数。
友元:一般来说,最好在类定义开始的地方或结束前的位置集中声明友元。我们可以将一个类声明为另一个类的友元,那么这个友元类的成员就可以访问它的所有成员了。
也可以将一个函数定义为一个类的友元,只需在开头加一个friend就可以:
class Myclass1 { int i; public: int geti()const{return i;} void show(Myclass&); };
<pre name="code" class="cpp">friend class Myclass1; // 友元类
friend void showData(); // 友元函数
我们还可以将一个类的成员函数声明为另一个类的友元:
friend void Myclass1::show(Myclass&);
我们需要按照如下方式设计:
1. 先定义Myclass类,声明show函数,不能定义它,在show函数使用Myclass之前必须先声明Myclass。
2. 接下来定义Myclass,包括对show友元函数的声明。
3. 最后定义show,此时它才可以使用Myclass的成员。
尽管重载函数的名字一样,但仍然是不同的函数,我们要在类中声明一组重载函数为友元时,需要逐个声明。
类的特性:
在常量成员函数中,理论上我们是不可以修改成员的值,但是我们可以添加关键字mutable来实现可以更改成员的值,我们可以追踪一个常量成员函数被调用了多少次:
mutable size_t find; // 为Myclass添加一个成员 void mutabledata()const{ ++find;} //添加函数
mutabledata函数是个常量成员函数,理论上不可以更改成员的值,但我们将find声明为mutable,我们就可以更改了。
我们还可以为类成员提供默认初始值,当我们提供一个初始值时,必须以符号= 或者花括号表示。
从const成员函数以引用的形式返回*this时,它的返回类型将是常量引用。
类的静态成员:
我们可以为Myclass类声明一个静态成员和静态成员函数:
static int data_static; static void showsta();
类的静态成员存在于任何类对象之外,它不与任何对象绑在一起,也不包含this指针。静态成员函数不能声明为const的,在静态成员函数内也不能使用this指针。
我们使用作用域运算符直接访问类的静态成员 函数:
int x; x = Myclass::showsta();
虽然静态成员不属于类的某个对象,但我们仍然可以使用类对象、引用或指针来访问静态成员。
静态成员可以在内部定义,也可以在外部定义,在外部定义时,不能重复static关键字。
void Myclass::showsta() { cout << data_static; }
通常情况下,类的静态成员不应该在类内初始化,如果我们将其声明为常量成员,则可以在内部定义。其初始值必须为常量表达式。
static constexpr double data_db = 1;
即使一个常量静态成员在类内定义,通常情况下,我们也应该在类的外部定义下该成员,但是不能带初始值:
constexpr double Myclass::data_db;
因为静态成员独立于任何对象,所以静态数据成员可以是不完整类型,特别的,静态数据成员的类型可以就是它所属的类类型,而非静态成员则受到限制,只能声明为它所属类的指针或引用,静态成员还可以作为默认实参。