栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c++中类的基本知识(1) 访问控制、友元、this指针

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++中类的基本知识(1) 访问控制、友元、this指针

类的基本思想是数据抽象和封装。数据抽象是一种依赖于接口和实现分离的编程。类的接口包括用户能执行的操作;类的实现包括类的数据成员、负责接口实现的函数体以及定义类所需的各种私有函数。
本文梳理一下类的基础知识和一些值得注意的点,参考《C++ Primer》第七章。

1 访问控制和封装

类中包括成员变量和成员函数,可以定义为 private 或者public。
比如定义一个Person类

class Person{
    int height;
    int age;
    ...
public:
    int get_height(){return height;}
    ...
}

这里,public之前的成员都是私有成员 ,类内可见,类外不可见。public之后的成员开放给类外访问,提供给用户一个使用此类的接口。

C++中定义一个类有struct和class两种类型,它们的区别在于默认的访问权限上。在第一个访问说明符前,struct默认是public,class默认是private。

虽然其数据成员是private的,但是类可以通过声明其他类或者函数为其友元,使得这些友元可以访问类的私有成员。
这里的友元可能有以下几种情况:

    作为类的接口之一的非成员函数其他类其他类中的成员
    这里需要注意的有几点,

一是声明其他类中的成员为友元时,要写清楚名字作用域,另一点在于,必须注意定义和声明之间的依赖关系。友元仅仅提供了访问权限,并不是真正的声明。
比如如下的例子:

struct X{
    friend void f();//提供访问权限,f()尚未声明
    X() {f();} //错误,此时f()并未声明
    void g();
    void h();
}

void X::g() {return f();} //f() 未声明
void f();
void X::h() {return f();}//正确,f的声明在作用域中了

c++中对于类的编译有如下的顺序:

    首先编译成员声明(不包括函数体),使得类中的所有名字完全可见;编译函数体

此外,c++中名字查找的顺序是:

    对应块中查找,只考虑名字使用前出现的声明;若没有找到,继续查早外层作用域;查找不到,程序报错。
    所以,对于如上的例子来说,X中的x()函数在类内的定义,由于无法查找到f()的声明,因此是错误的,上面的友元声明仅仅提供了访问权限,并不是真正的声明。直到f()被声明了,类外的x()定义才是有效的。

综上,在声明其他类的成员函数为友元时,要严格注意声明和定义的依赖关系。

2 this那些事 this是类中的隐式参数

c++类中的成员函数,有的看似没有参数,实际上有隐含的参数。比如回到上面的person类:

class Person{
    int height=180;//类内初始值
    int age=20;
    ...
public:
    int get_height(){return height;}
    ...
}

int main(){
    Person A;
    cout< 

这里,在调用A的成员函数get_height()时,看似get_height()是一个无参数的函数,实际上执行过程为:

   get_height(&A)

成员函数使用一个叫this的隐式参数来访问调用它的那个对象。调用成员函数时,用对象的地址初始化this。在成员函数内部可以直接调用函数对象成员,这种直接访问被看作this的隐式引用。实际上get_height()也可以写成如下形式:

   int get_height(){return this->height;}
this默认情况下是指向类非常量版本的常量指针

比如在上面的person类中,this的默认类型是person *const。this的初始化同样需要遵循初始化规则,所以默认情况下this不能被绑定到常量对象上。因此,对于常量对象,它不能调用普通成员函数。
如果想要使this声明为指向常量的指针,可以将const关键字放在成员函数的参数列表之后,这种成员函数称为常量成员函数。

    person::get_height() const {return height;}
    //可以理解为
    person::get_height() (const person *const this) {return this->height;}

返回*this的成员函数

返回引用和非引用的区别

返回引用,则返回一个左值,对该返回值的操作可以直接改变对象

不是返回引用,则返回的是一个临时值副本

class Screen {
public:
    Screen &set(char);
    Screen &set(pos,pos,char);
}

inline Screen &Screen::set(char c){
    contents[cursor] = c;
    return *this;
}

inline Screen &Screen:set(pos r, pos l,char ch){
    contents[r*width+col] = ch;
    return *this;
}

调用上述函数

myScreen.move(4,0).set('#');//move返回左值,可修改

而如果不是返回一个引用,则返回的是一个副本、右值。

#include 
using namespace std;

class person{
    int height=180;
public:
     person set_height(int _height){
         height=_height;
         return *this;
     }
     void print_height(){
         cout<  

上述函数调用后会显示:

test.cpp:20:36: error: taking address of rvalue [-fpermissive]
   20 |     cout<<(int) &(A.set_height(190))< 

const成员函数返回的是常量引用

假如函数display是常量成员函数,则下面的操作是错误的

Screen myScreen;
myScreen.display(cout).set('*');

虽然mySreen不是常量对象,但是display返回的是常量引用

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/767096.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号