C++ Primer 学习笔记_50_类与数据抽象 --类作用域

--类作用域

引言:

每个类都定义了自己的新作用域与唯一的类型。即使两个类具有完全相同的成员列表,它们也是不同的类型。每个类的成员不同与任何其他类(或任何其他作用域)的成员

class First
{
public:
    int memi;
    double memd;
};

class Second
{
public:
    int memi;
    double memd;
};

First obj1;
Second obj2 = obj1; //Error

1、使用类的成员

在类作用域之外,成员只能通过对象或指针使用成员访问操作符.或->来访问。这些操作符左边的操作数分别是一个类对象或指向类对象的指针。

还有一些直接通过类使用作用域操作符(::)来访问。如:定义类型的成员,Screen::index,使用作用域操作符来访问。

2、作用域与成员定义

尽管成员是在类的定义体之外定义的,但成员定义就好像它们是在类的作用域中一样。

//一旦看到成员的完全限定名,就知道该类定义是在类作用域中
double Sales_item::avg_price() const
{
    if (units_sold)
    {
        return revenue / units_sold;
    }

    return 0;
}

3、形参表和函数体处于类作用域中

在定义于类外部的成员函数中,形参表和成员函数体都出现在成员名之后。这些都是在类作用域中定义,所以可以不用限定而引用其他成员。

char Screen::get(index r,index c) const
{
    index row = r * width;
    return contents[row + c];
}

4、函数返回类型不一定在类作用域中

与形参类型相比,返回类型出现在成员名字前面。如果函数在类定义体之外定义,则用于返回类型的名字在类作用域之外。如果返回类型使用由类定义的类型,则必须使用完全限定名。

class Screen
{
public:
    typedef std::string::size_type index;
    index get_cursor() const;

    //...
};

//由于index出现在函数名被处理之前,所以代码不在类作用域内。
inline Screen::index Screen::get_cursor() const
{
    return cursor;
}

//P381 习题2.16
//error: ‘index‘ does not name a type
index Screen::get_cursor() const
{
    return cursor;
}

类作用域中的名字查找

一直以来,我们程序的名字查找:

1)首先,在使用该名字的块中查找名字的声明。只考虑在该项使用之前声明的名字。

2)如果在1)中找不到,则在包围的作用域中查找。

如果找不到任何声明,则出错。

类的定义实际上是在两个阶段中处理:

1)首先,编译器声明;

2)只有在所有成员出现之后,才编译他们的定义本身。

1、类成员声明的名字查找

按照以下方式确定在类成员的声明中用到的名字:

1)检查出现在名字使用之前的类成员的声明。

2)第一步查找不成功,则价差包含类定义的作用域中出现的声明以及出现在类定义之前的声明!

如:

typedef double Money;
class Account
{
public:
    Money balance()
    {
        return bal;
    }

private:
    Money bal;
};

【谨记:】

必须是在类中先定义类型名字,才能将它们用作数据成员的类型,或者成员函数的返回类型或形参类型。

一旦一个名字被用作类型名,则该名字就不能被重复定义:

typedef double Money;
class Account
{
public:
    Money balance()
    {
        return bal;
    }

private:
    typedef long double Money;  //Error
    Money bal;
};

2、类成员定于中的名字查找

1)首先检查成员函数局部作用域中的声明。

2)如果在成员函数中找不到该名字的声明,则检查对所有类成员的声明。

3)如果在类中找不到该名字的声明,则检查在此成员函数定义之前的作用域中出现的声明。

3、类成员遵循常规的块作用域名字查找

在程序中尽量不要使用相同名字的形参和成员:

int height;
class Screen
{
public:
    typedef int index;

    //由于在函数形参中定义了height,
    //所以此处的height形参会屏蔽名为height的成员
    void dummy_fcn(index height)
    {
        cursor = width * height;
    }

private:
    index cursor;
    index height,width;
};

尽管类的成员被屏蔽了,但是仍然可以通过使用类名来限定成员名或显式使用this指针来使用:

    void dummy_fcn(index height)
    {
        cursor = width * this -> height;
        //这两条语句作用相同
        cursor = width * Screen::height;
    }

4、函数作用域之后,在类作用域中查找

如果想要使用height成员,最好的方式还是为形参定义一个不同的名字:

    void dummy_fcn(index ht)
    {
        cursor = width * height;
    }

尽管height是先在dummy_fcn中使用,然后再声明,但是编译器还是确定这里用的是名为height的数据成员。

5、类作用域之后,在外围作用域中查找

尽管全局对象height在类中被数据成员height屏蔽了,但还可以通过全局作用域确定操作符来限定名字,仍然可使用它:

    void dummy_fcn(index height)
    {
        cursor = width * ::height
    }

6、在文件中名字的出现初确定名字

当成员定义在类定义的外部时,名字查找的第3步不仅要考虑在Screen类定义之前的全局作用域中的声明,而且要考虑在成员函数定义之前出现的全局作用域声明:

class Screen
{
public:
    typedef int index;
    void setHeight(index);

private:
    index height;
};

Screen::index verify(Screen::index);

void Screen::setHeight(index val)
{
    /*
    *val由形参定义
    *verify是全局函数
    *height是类的数据成员
    */
    height = verify(val);
}

//P385 习题12.17
//编译查看错误
class Screen
{
public:
    void setHeight(index);

private:
    index height;
    typedef int index;
};

//习题12.18
typedef string Type;
Type initVal();

class Exercise
{
public:
    Type setVal(Type);

private:
    Type val;   //string val;
};

Type Exercise::setVal(Type parm)
{
    val = parm + initVal();
    return val;
}
时间: 2024-10-10 23:41:37

C++ Primer 学习笔记_50_类与数据抽象 --类作用域的相关文章

C++ Primer 学习笔记_81_模板与泛型编程 --类模板成员[续1]

模板与泛型编程 --类模板成员[续1] 二.非类型形参的模板实参 template <int hi,int wid> class Screen { public: Screen():screen(hi * wid,'#'), cursor(hi * wid),height(hi),width(wid) {} //.. private: std::string screen; std::string::size_type cursor; std::string::size_type height

C++ Primer 学习笔记_82_模板与泛型编程 --类模板成员[续2]

模板与泛型编程 --类模板成员[续2] 六.完整的Queue类 Queue的完整定义: template <typename Type> class Queue; template <typename Type> ostream &operator<<(ostream &,const Queue<Type> &); template <typename Type> class QueueItem { friend clas

C++ Primer 学习笔记_72_面向对象编程 --句柄类与继承[续]

面向对象编程 --句柄类与继承[续] 三.句柄的使用 使用Sales_item对象能够更easy地编写书店应用程序.代码将不必管理Item_base对象的指针,但仍然能够获得通过Sales_item对象进行的调用的虚行为. 1.比較两个Sales_item对象 在编写函数计算销售总数之前,须要定义比較Sales_item对象的方法.要用Sales_item作为关联容器的keyword,必须能够比較它们.关联容器默认使用keyword类型的小于操作符,可是假设给Sales_item定义小于操作符,

C++ Primer 学习笔记_80_模板与泛型编程 --类模板成员

模板与泛型编程 --类模板成员 引言: 这一节我们介绍怎样实现前面提到的Queue模板类. 标准库将queue实现为其他容器之上的适配器.为了强调在使用低级数据结构中设计的编程要点,我们将Queue实现为链表.实际上,在我们的实现中使用标准库可能是个更好的决定!!-_-. 1.Queue的实现策略 如图所示,我们实现两个类: 1)QueueItem类表示Queue的链表中的节点,该类有两个数据成员item和next: a. item保存Queue中元素的值,它的类型随Queue的每个实例而变化:

C++ Primer 学习笔记_103_特殊工具与技术 --类成员指针

特殊工具与技术 --类成员指针 成员指针可以做到:获得特定成员的指针,然后从一个对象或别的对象获得该成员.成员指针应该包含类的类型以及成员的类型. 一.声明成员指针 测试类: class Screen { public: typedef std::string::size_type index; char get() const; char get(index ht,index wd) const; private: std::string contents; index cursor; ind

C++ Primer 学习笔记_71_面向对象编程 --句柄类与继承

面向对象编程 --句柄类与继承 引言: C++中面向对象编程的一个颇具讽刺意味的地方是:不能使用对象支持面向对象编程,相反,必须使用指针或引用. void get_prices(Item_base object, Item_base *pointer, Item_base &reference){ //需要根据指针或引用实际所绑定的类型进行调用 cout<< pointer ->net_price(1)<< endl; cout<< reference.n

C++ Primer 学习笔记_81_模板与泛型编程 -类模板成员[续一]

模板与泛型编程 --类模板成员[续1] 二.非类型形参的模板实参 template <int hi,int wid> class Screen { public: Screen():screen(hi * wid,'#'), cursor(hi * wid),height(hi),width(wid) {} //.. private: std::string screen; std::string::size_type cursor; std::string::size_type height

C++ Primer 学习笔记_82_模板与泛型编程 -类模板成员[续二]

模板与泛型编程 --类模板成员[续2] 六.完整的Queue类 Queue的完整定义: template <typename Type> class Queue; template <typename Type> ostream &operator<<(ostream &,const Queue<Type> &); template <typename Type> class QueueItem { friend clas

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员)、拷贝构造函数

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员).拷贝构造函数  从概念上将,可以认为构造函数分为两个阶段执行: 1)初始化阶段: 2)普通的计算阶段.计算阶段由构造函数函数体中的所有语句组成. 一.构造函数初始化列表 推荐在构造函数初始化列表中进行初始化 1.对象成员及其初始化 <span style="font-size:14px;">#include <iostream> using namespace std;