重学C++ (七) 类 概览
2016-01-22 16:55
295 查看
1.类内部定义的函数默认为inline;
2.可以声明一个类而不定义它:
不完全类型只能以有限方式使用,不能定义该类型的对象,只能定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数;
3.因为只有当类定义体完成后才能定义类,所以类不能具有自身类型的数据成员(只能是指向自身类型的指针或引用);
4.定义一个类,相当于定义了一个类型,之后可以定义该类型的对象;(一般而言)定义类型时不进行类型分配,而定义对象时,将为其分配存储空间;
5.const成员函数:在普通的非const成员函数中,this是一个指向类类型的const指针,即可以改变this所指向的对象的值,但不能改变this所保存的地址;在const成员函数中,this是一个指向const类类型的const指针,不能改变this所指向的对象,也不能改变this保存的地址;
*const成员函数不能调用非const成员函数:因为在调用过程中,const成员函数会把const的this隐式传递给非const成员函数,这样子把一个常量地址赋给一个变量地址是不允许的;
6.可变数据成员:
可将数据成员声明为mutable,它不能为const;const成员函数可以改变mutable成员;
7.如果返回类型使用由类定义的类型,必须使用完全限定名:
8.基于const的重载:
在一个类中(比如Student类),print() const 和 print() 两个成员函数可以同时存在,因为它们的函数签名是不同的,print() const的隐藏参数是const Student ,而print()的隐藏参数是Student ;
9.构造函数:
构造函数可以被重载,每个对象只能(并且必须)调用所在类的其中一个构造函数;
构造函数不能声明为const:因为其工作是用来初始化对象;
9.1构造函数的初始化式
构造函数的初始化式只能在构造函数的定义而不是声明中指定;
为体现这一点的区别,我们看看哪些情况只能用初始化列表:
没有默认构造函数的类类型成员,以及const或引用类型的成员,都必须在构造函数初始化列表中初始化!
因为:我们可以初始化const对象或引用类型的对象,但是不能对它们赋值。而对于没有为类成员提供初始化式的情况,编译器会隐式使用其默认构造函数,当该类没有默认构造函数时,编译器的尝试将会失败。
**成员初始化的次序:成员被初始化的次序就是定义成员的次序,而与列表上的顺序无关!
初始化式可以是任意表达式;
9.2默认构造函数
当一个类没有定义任何构造函数时,编译器才会自动生成一个默认构造函数;
使用默认构造函数时,注意以下区别:
9.3构造函数定义的隐式转换
为防止隐式转换,可添加explicit关键字:
**explicit关键字只能用于【类内部】的构造函数【声明】上。
通常,单形参构造函数应该为explicit,以避免错误,之后如果需要转换,可以显式进行:
10.static类成员
通常,非static数据成员存在于类类型的每个对象实例中,而static数据成员不同,它独立于该类的任意对象而存在,即每个static数据成员是类类型关联,不与对象实例关联;
static成员函数没有this形参(因此不能声明为const),它可以直接访问所属类的static成员,但不能直接使用非static成员;另外,static成员函数不能被声明为虚函数;
static成员遵循正常的公用/私有访问规则;
如果static成员函数在类外部定义,则只需要在内部声明时指定static;
**注意,static数据成员在类中仅进行【声明】,它不通过类构造函数初始化,而应该在定义时初始化,它必须在类定义体【外部】定义(有且仅有一次),且定义时不能标示为static;
一个例外:只有初始化式是一个常量表达式,整型const static数据成员就可以在类的定义体中初始化:
**static成员不是类对象实例的组成部分,它的类型可以是该成员所属类的类型:
2.可以声明一个类而不定义它:
[code]class Screen; //前向声明,此时Screen是一个不完全类型
不完全类型只能以有限方式使用,不能定义该类型的对象,只能定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数;
3.因为只有当类定义体完成后才能定义类,所以类不能具有自身类型的数据成员(只能是指向自身类型的指针或引用);
4.定义一个类,相当于定义了一个类型,之后可以定义该类型的对象;(一般而言)定义类型时不进行类型分配,而定义对象时,将为其分配存储空间;
5.const成员函数:在普通的非const成员函数中,this是一个指向类类型的const指针,即可以改变this所指向的对象的值,但不能改变this所保存的地址;在const成员函数中,this是一个指向const类类型的const指针,不能改变this所指向的对象,也不能改变this保存的地址;
*const成员函数不能调用非const成员函数:因为在调用过程中,const成员函数会把const的this隐式传递给非const成员函数,这样子把一个常量地址赋给一个变量地址是不允许的;
6.可变数据成员:
可将数据成员声明为mutable,它不能为const;const成员函数可以改变mutable成员;
7.如果返回类型使用由类定义的类型,必须使用完全限定名:
[code]class Screen { public: typedef std::string::size_type index; index get_cursor() const; private: index cursor; }; inline Screen::index Screen::get_cursor() const { return cursor; }
8.基于const的重载:
在一个类中(比如Student类),print() const 和 print() 两个成员函数可以同时存在,因为它们的函数签名是不同的,print() const的隐藏参数是const Student ,而print()的隐藏参数是Student ;
9.构造函数:
构造函数可以被重载,每个对象只能(并且必须)调用所在类的其中一个构造函数;
构造函数不能声明为const:因为其工作是用来初始化对象;
9.1构造函数的初始化式
构造函数的初始化式只能在构造函数的定义而不是声明中指定;
[code]//初始化列表 Sales_item::Sales_item(const string &book): isbn(book), units_sold(0), revenue(0.0) {} //无初始化列表 Sales_item::Sales_item(const string &book) { isbn = book; units_sold = 0; revenue = 0.0; } /* 区别: * 初始化列表的版本是【初始化】数据成员; * 另一个版本是先初始化,然后在函数体中对数据成员【赋值】。 * 构造函数两个执行阶段:1.初始化阶段;2.普通的计算阶段。 * 对于第二个版本,初始化阶段中,在局部作用域中这些成员不被初始化, * 在全局作用域中初始化为0; */
为体现这一点的区别,我们看看哪些情况只能用初始化列表:
没有默认构造函数的类类型成员,以及const或引用类型的成员,都必须在构造函数初始化列表中初始化!
因为:我们可以初始化const对象或引用类型的对象,但是不能对它们赋值。而对于没有为类成员提供初始化式的情况,编译器会隐式使用其默认构造函数,当该类没有默认构造函数时,编译器的尝试将会失败。
**成员初始化的次序:成员被初始化的次序就是定义成员的次序,而与列表上的顺序无关!
[code]class X { int i; int j; public: // undefined: i is initialized before j // i先于j初始化,此时如果用j来初始化i,结果是未定义的 X(int val): j(val), i(j) { } };
初始化式可以是任意表达式;
9.2默认构造函数
当一个类没有定义任何构造函数时,编译器才会自动生成一个默认构造函数;
使用默认构造函数时,注意以下区别:
[code]Sales_item myobj(); //error, declares a function, not an object! Sales_item myobj; //ok,使用默认构造函数 Sales_item myobj = Sales_item(); //ok,用一个匿名,空的对象来初始化myobj;
9.3构造函数定义的隐式转换
[code]class Sales_data { public: Sales_data(const std::string &book = ""): isbn(book), units_sold(0), revenue(0.0) { } Sales_data(std::istream &is); };
[code]//same_isbn的参数类型应该为Sales_data,但是由于隐式转换,这里cin隐式转换为Sales_data类型(通过第二个构造函数),创建了一个临时的Sales_data对象,并传递给same_isbn,一旦函数结束,该对象就不能访问了,这可能导致错误。 item.same_isbn(cin);
为防止隐式转换,可添加explicit关键字:
[code]class Sales_data { public: explicit Sales_data(const std::string &book = ""): isbn(book), units_sold(0), revenue(0.0) { } explicit Sales_data(std::istream &is); };
**explicit关键字只能用于【类内部】的构造函数【声明】上。
通常,单形参构造函数应该为explicit,以避免错误,之后如果需要转换,可以显式进行:
[code]item.same_isbn(Sales_data(cin));
10.static类成员
通常,非static数据成员存在于类类型的每个对象实例中,而static数据成员不同,它独立于该类的任意对象而存在,即每个static数据成员是类类型关联,不与对象实例关联;
static成员函数没有this形参(因此不能声明为const),它可以直接访问所属类的static成员,但不能直接使用非static成员;另外,static成员函数不能被声明为虚函数;
static成员遵循正常的公用/私有访问规则;
[code]//假设类Account有一个 static double rate();成员 Account ac; double rate; rate = ac.rate(); rate = Account::rate();
如果static成员函数在类外部定义,则只需要在内部声明时指定static;
**注意,static数据成员在类中仅进行【声明】,它不通过类构造函数初始化,而应该在定义时初始化,它必须在类定义体【外部】定义(有且仅有一次),且定义时不能标示为static;
[code]//定义 double Account::myStaticMem = initRate();
一个例外:只有初始化式是一个常量表达式,整型const static数据成员就可以在类的定义体中初始化:
[code]class Account { public: static double rate() { return interestRate; } static void rate(double); private: static const int period = 30;// period is a constant expression double daily_tbl[period]; //ok }; //但是数据成员仍然需要在类的定义体外定义!只是不需要再初始化了。 const int Account::period;
**static成员不是类对象实例的组成部分,它的类型可以是该成员所属类的类型:
[code]class Bar { public: // ... private: static Bar mem1; // ok: static member can have incomplete type Bar *mem2; // ok: pointer member can have incomplete type Bar mem3; // error: data members must have complete type };
相关文章推荐
- C++之路进阶——左偏堆(罗马游戏)
- Opencv+C++之身份证识别(一)
- WM_CTLCOLOR消息
- C语言字符串解析
- C++编程指向成员的指针以及this指针的基本使用指南
- C++中的static关键字的总结
- 历史上出现过的主流C/C++ 编译器都有哪些?
- C++实现类、类的成员函数、主函数分离
- 详解C++编程中的嵌套类的声明与其中的函数使用
- c++ 纯虚函数
- C语言 百炼成钢9
- C++智能指针简单剖析
- Microsoft Visual C++ 9.0 is required
- 最大公约数与最小公倍数(c语言)
- [土狗之路]coursera上C++基础第10周作业(下)
- 关于 explicit 的一些学习
- C++指针理解
- C++指针理解
- C++ Scope Exit
- x265-1.7版本-common/cudata.cpp注释