您的位置:首页 > 编程语言 > C语言/C++

重学C++ (七) 类 概览

2016-01-22 16:55 295 查看
1.类内部定义的函数默认为inline;

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
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: