c++类和对象 (const,内联,友元,静态成员)

一, const

class Date
{
public:
    Date(int year = 1900,int month = 1,int day = 1)
        :_year(year),
        _month(month),
        _day(day)
    {}

    void Show()
    {
        cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1;
    d1.Show();
    return 0;
}

还是拿日期类举例,看这段代码,d1调用Show()函数没有任何问题,但是,如果d1的类型变为 const Date d1,那结果将会如何呢?


编译器给出了如下的错误提示:传进去的 this 指针是const Date类型的,但是函数并没有 const

所以我们要改正只需要将Show()函数的形参改为const类型即可,那么以下这种改法可行吗?

    void Show(const Date this)
    {
        cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
    }

答案当然是不行了,因为this是编译器默认处理的,我们无法干涉,正确的写法是这样的

    void Show() const
    {
        cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
    }

在函数名后加一个 const,编译器发现这里有一个const的时候,就会默认的将 this指针定义为 const Date的类型

以下的几种调用可以执行吗


我们需要知道,const这个关键字其实是把我们的变量权限缩小,原本d1是可读可写的,加上const疑惑就成为只读的了

上面我们已经讨论过第一种是不可行的,我们无法用一个非const的函数来接收const类型的实参,因为我自己本身是只读的,传给了函数就变成了可读可写的,这属于权限放大,当然是不可以的,我自己都不能改变自己,别人凭什么可以改变我

不过,修改成第二种就可以了,传给函数以后权限并没有改变,依旧是只读的

第三个当然是可以的,非const参数传给非const函数,可以运行成功

第四个其实也是可行的,把一个可读可写的变量传给一个只读的函数,属于权限缩小,所以没问题

总结: 权限缩小没问题,权限放大不行哦

二、内联( inline )

这里我们不得不提起 C 语言中一个重要的东西 -- 宏

宏分为 宏函数 和 宏变量

宏的优缺点:

宏变量:代码复用性强(只改变宏就可以修改很多地方)

              提高性能(在预处理阶段就进行了宏替换)

              不方便调试

宏函数: 代码冗余

               容易误用

               可读性差

               没有安全性检查

               ...    

内联函数是在 c++中可以用来替换宏的机制

以inline修饰的函数叫做内联函数,编译时C++编译器会调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。

1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的的函数不适宜使用内联。

2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。

3. inline必须函数定义放在一起,才能成为内联函数,仅将inline放在声明前是不起不作用的。

4. 定义在类内的成员函数默认定义为内联函数。

inline void Date::Show()
{
    cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}

注意:尽量用 const,enum,inline替换#difine

三、友元

在C++中友元函数允许在类外访问该类中的任何成员,就象成员函数一样,友元函数用关键字friend说明。

1. 友元函数不是类的成员函数。

2. 友元函数可以通过对象访问所有成员,私有和保护成员也一样。

友元函数其实大大的破换了封装性,所以建议一般不要使用,不过存在即有他的道理,这里举一个特殊的例子说明友元存在的必要性

重载输入输出运算符( << , >>)时,如果我们不使用友元函数,就必须定义成如下的样子

    //重载运算符 >> <<
    ostream& operator<<(ostream& out)
    {
        out<<_year<<"-"<<_month<<"-"<<_day<<endl;
        return out;
    }

所以,即使在这时也破坏了封装性,但是,权衡了利弊,我们选择提高可读性,所以使用友元函数

#include <iostream>
using namespace std;

class Date
{
public:
    Date(int year = 1900,int month = 1,int day = 1)
        :_year(year),
        _month(month),
        _day(day)
    {}

    //重载运算符 >> <<
    friend ostream & operator<< ( ostream& out , const Date& d  );
    friend istream & operator>> ( istream& in , Date& d );

private:
    int _year;
    int _month;
    int _day;
};

ostream & operator<<( ostream& out , const Date& d )
{
    out<<"year:" <<d. _year<<endl ;
    out<<"month:" <<d. _month<<endl ;
    out<<"day:" <<d. _day<<endl <<endl;
    return out ;
}
    
istream & operator>> ( istream& in , Date& d )
{
    cin>>d._year;
    cin>>d._month;
    cin>>d._day;
    return in;
}
int main()
{
    Date d1;
    cin>>d1;
    cout<<d1;

    return 0;
}

3、友元类

将一个类B定义为另一个类A的友元类,那么B就可以访问A中所有的成员


友元破坏了C++程序的封装性,尽量不适用友元,只在恰当的时候适用

四、静态成员

静态变量:存放在全局区

当该类需要一个所有成员对象所共享的变量时,这时候最好适用静态成员(static)

#include <iostream>
using namespace std;

class AA
{
public:
    AA()
    {
        cout<<"AA()"<<endl;
        ++_count;
    }
    void show()
    {
        cout<<"count = "<<_count<<endl;
    }
private:
    int _a;
    static int _count;
};

//静态成员变量需在类外初始化
int AA::_count = 0;

int main()
{
    AA a1;
    a1.show();
    AA a2;
    a2.show();
    return 0;
}


注意:静态成员函数没有隐含this指针参数,所以可以使用类型::作用域访问符直接调用静态成员函数。

普通的成员函数必须需要成员变量来调用



但是静态成员函数还有另一种调动方法


因为静态成员函数没有this指针,不需要传参,所以也就不需要使用成员变量来调用了

那么,在静态成员函数中可以调用非静态成员函数嘛


答案是不行的,非静态成员函数有隐藏的this指针,在其内部可以访问成员变量,但是静态的成员函数GetCount根本没有this指针,也就无法传给show函数,所以也就无法调用show函数

同理,在静态成员函数中,也不可以访问普通成员变量,因为访问成员变量也需要this指针

那么,普通的成员函数可以访问静态的成员函数嘛?当然可以,静态成员函数属于整个类域,只要在类里面,就可以访问,在类外的话如果输public才可以访问

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值