C++ Primer 类 12.1-12.2 this ,定义

来源:互联网 发布:淘宝历史比价 编辑:程序博客网 时间:2024/06/05 17:05

12.1 类的定义和声明

类由类成员组成。类成员包括属性,字段,成员函数,构造函数,析构函数等组成。 

类设计应该遵从抽象封装性。

类抽象性指对于类的使用者来说只需知道类接口即可使用类功能。类的具体实现由设计者负责。即使某个功能发生了变更但由于使用者是以接口方式调用类所以用户代码无需做任何修改。

类封装性指类用户只需知道类的功能无需了解具体实现。实现代码对用户来说不可见。 

C++类没有访问级别限限制,定义类时不能用public 或 private 做修饰。类成员有访问级别,可以定义 public protect private

#include<iostream>

using namespace std;

 

class Screen

{

            public:

                         //类成员只能声明不允许定义 替换成stringname("tom")

                        //会产生编译错误, 数据成员初始化工作在构造函数中执行

                        string  name;           

 

                        // 给类定义别名类型成员 index 由于别名要在外部访问所

                        //以一定要定义在 public

                        typedefstd::string::size_type index;

 

                        //构造函数

                        Screen( index cur =100);

 

                        //析构函数

                        ~Screen();

 

                        // 内部定义的函数,等价于inline

                        char get() const {return contents[cursor]; }

 

                        // 内部声明一个成员函数(无定义),且函数是内联的inline

                        //表示在编译时该声明会被替换成定义语句

                        inline char get(indexht, index wd) const;

 

                        // 内部声明一个成员函数(无定义)

                        index get_cursor()const;

 

            private:

                        std::string contents;

                        index cursor;

                        index height,width;

};

 




#include<iostream>

#include"def_class.h"

using namespace std;

 

inline Screen::Screen(Screen::indexcur ){

            cursor = cur;

            width = 20;

            height = 10;

}

 

inlineScreen::~Screen(){

 

}

 

// 定义类 Screen 的成员函数get 具体实现

charScreen::get(index r, index c) const

{

 

            index row = r * width;    // compute the row location

 

            return contents[row + c]; // offsetby c to fetch specified character

 

}

 

 

// 定义类 Screen 的成员函数get_cursor 具体实现,且是内联的

 

inline Screen::indexScreen::get_cursor() const

//inline indexScreen::get_cursor() const

{

 

            return cursor;

 

}

 

#include<iostream>

#include"def_class.h"

 

using namespace std;

 

int main( int argc ,char *argv[] ){

            Screen wnd;

            size_t cur;

 

            /* operate member function */

            cur = wnd.get_cursor();

            cout<<cur<<endl;

 

            return 0;

}


注:1.类的inline修饰符可以放在类内部申明也可以放在外部定义。一般放在内部声明便于理解。

类定义完毕后一定要加上封号结束符;。

类数据成员只允许声明不允许定义;

2.编译的时候应该这样

g++ -fkeep-inline-functions main.cpp def_class.cpp

分析原因,由于def_class.h所有函数在实现文件def_class.cpp中均显式声明为内联,根据g++编译的默认选项是-fno-keep-inline-functions,如果函数被内联,则不存在对函数的调用,编译程序将不生成函数体,因此虽然main.cpp中include了相关函数的定义,但是找不到这些函数的实现,自然出现错误"undefinedreference toXXX"。 
修改该选项为-fkeep-inline-functions,则及时不存在对函数的调用,编译程序也会生成函数体,于是世界又清静了。



12.2 this指针

1.这些函数的返回类型是 Screen&,指明该成员函数返回对其自身类类型的对象的引用。

2.在普通的非 const 成员函数中,this 的类型是一个指向类类型的 const 指针。可以改变 this 所指向的值,但不能改变 this 所保存的地址。

3.基于成员函数是否为 const,可以重载一个成员函数;同样地,基于一个指针形参是否指向 const( 7.8.4),可以重载一个函数。const 对象只能使用 const成员。非 const 对象可以使用任一成员,但非 const 版本是一个更好的匹配。

4. 类对象包含一个 this 指针指向自身(当前的实例对象)且无法更改指针指向。在普通的非 const 成员函数中,this 的类型是一个指向类类型的 const 指针。可以改变 this 所指向的值,但不能改变 this 所保存的地址。在 const 成员函数中,this 的类型是一个指向 const 类类型对象的 const 指针。既不能改变 this 所指向的对象,也不能改变 this 所保存的地址。

    基于成员函数是否为 const,可以重载一个成员函数;同样地,基于一个指针形参是否指向 const可以重载一个函数。

class mycls

{

    public:

        mycls(){}; // 想要定义 const mycls a; 必须要显示定义默认构造函数

        mycls &Get(){ return *this; };

        const mycls &Get() const { return*this; }; // 想如果const函数返回this引用或指针; 必须要返回const指针或引用,因为无法用const对象(this)初始化非const对象。

 

};

 

const mycls b;

mycls b1 = c.Get();// 调用const版Get函数

const mycls b2 =c.Get(); // 调用const版Get函数

// b1 b2 定义时会调用类的拷贝函数。b1,b2是Get返回值的副本,b1还会将常量副本转变成变量

 

mycls &b3 =c.Get(); // 错误,不能用 const &mycls 初始化 &mycls (指针或者引用类型不能用常量初始化变量)

const mycls &b4 =c.Get();

 

 

mycls a;

mycls a1 = a.Get();// 调用非const版Get函数

const mycls a2 =a.Get(); // 调用非const版Get函数

       由此可见调用那个版本和调用对象是否const有关系,const对象会调用const版本,非const对象会调用非const版本。   

       引用网上的总结:

成员函数具有const重载时,类的const对象将调用类的const版本成员函数,类的非const对象将调用非const版本成员函数。

如果只有const成员函数,类的非const对象也可以调用const成员函数。                         ——这个思路来描述很囧。下同。

如果只有非const成员函数,类的const对象…额,不能调用非const成员函数。               ——其实跟上一句的意思是一样的:const对象只能调用它的const成员函数。

总的来说,就是当我们调用一个成员函数时,编译器会先检查函数是否有const重载,如果有,将根据对象的const属性来决定应该调用哪一个函数。如果没有const重载,只此一家,那当然就调用这一个了。这时编译器亦要检查函数是不是没有const属性而调用函数的对象又有const属性,若如此,亦无法通过编译。

0 0