深度探究类和对象

基础知识请参照 >类&对象<

【const成员函数】

  const成员函数,const修饰的是this指针指向的对象,保证调用这个const成员函数的对象在函数内不被修改。

描述

class Date{
public:
    void show()
    {
        cout << _year << "-" << _month << "-" << _day << endl;
    }
    void show() const
    {
        cout << _year << "-" << _month << "-" << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    const Date d;
    d.show();
    system("pause");
    return 0;
}

描述

  • const对象只能调用const成员函数

描述

  • 非const对象既能调用非const成员函数也能调用const成员函数

描述

  • const成员函数只能调用其他const成员函数

描述

  • 非const成员函数既能调用其他非const成员函数也能调用const成员函数

描述

结论:
  1.如果成员函数中需要修改成员变量,则不能加const
  2.若只读,则最好加const,因普通对象和const对象都可调该函数

  • 取地址运算符重载
Date* operator&()
{
    return this;
}

const Date* operator&() const
{
    return this;
}

描述

  一般来说,取地址操作符由系统给出,不用重载。但当你不想让取地址符取到地址时,就需要重载。这样的方式有两种:

1.返回空

描述

2.只声明,不定义

描述
此时编译能过,但链接失败。

【内联】

定义:

  • 用inline修饰的函数,叫内联函数。编译时C++编译器会将内联函数展开,没有函数的压栈开销,提升程序运行速率

可以看出,内联类似于宏。宏的优缺点:

  • 优点:
      1.宏常量——增强可维护性
      2.宏函数——增强效率(预处理时宏替换,没有压栈)

  • 缺点
      1.不方便调试
      2.没有类型安全检查
      3.宏可读性比较差,可维护性比较差(宏函数),容易出错

宏函数书写方式:

描述

由于宏函数有时候可读性比较差,容易出错,由此C++提出内联函数。

inline int Add(int a, int b)
{
    return a + b;
}

int main()
{
    printf("%d\n", Add(2, 3));
    return 0;
}

内联函数在Debug中,也会调用函数,形成栈帧,而在Release中会被优化,直接展开

描述

内联特点:

  1. inline是一种空间换时间做法,省去压栈开销。但代码很长或有递归,循环时不宜用内联。
  2. 编译器会自动优化inline,若函数体内有递归等,编译器优化会忽略内联
  3. inline必须和函数定义放在一起,仅放声明中不起作用,无法形成内联函数
  4. 定义在类内的成员函数默认定义为内联函数

尽量用const,enum,inline替换 #define

【友元】

友元函数:

  1. 友元函数不是类的成员函数,只是用关键字在类中说明。
  2. 友元函数可以通过对象访问所有成员,包括私有和保护。
class Date
{
    friend void show(const Date& d);     //友元函数
public:
    Date(int year = 2018, int month = 3, int day = 30)
        :_year(year)
        , _month(month)
        , _day(day)
        {

        }

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

void show(const Date& d)    //在类外定义的函数,需要访问类中的私有成员需要定义友元函数
{
    cout << d._year << "-" << d._month << "-" << d._day << endl;
}

int main()
{
    Date d;
    show(d);
    system("pause");
    return 0;
}

友元类:

  1. 整个类是另一个类的友元
  2. 友元类的每个成员函数都是另一个类的友元函数,可以访问另一个类中所有成员,包括私有和保护
class Date
{
    friend void show(const Date& d);        //友元函数
    friend class AA;        //友元类
public:
    Date(int year = 2018, int month = 3, int day = 30)
        :_year(year)
        , _month(month)
        , _day(day)
        {

        }

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

void show(const Date& d)
{
    cout << d._year << "-" << d._month << "-" << d._day << endl;
}

class AA
{
public:
    void show(const Date& d)        //AA类想访问Date类的私有成员,需定义友元类
    {
        cout << d._year << "-" << d._month << "-" << d._day << endl;
    }
    void Modift(Date& d)
    {
        d._year = 1900;
    }
};

int main()
{
    Date d;
    show(d);

    AA aa;
    aa.show(d);
    aa.Modift(d);
    show(d);

    system("pause");
    return 0;
}

注意:友元在一定程度上破坏了C++的封装性,所以应在适当的地方使用友元。
(低耦合高维护性,高耦合低维护性)

输入输出运算符重载(友元函数应用):
系统给出的输入输出运算符支持内置类型,不支持自定义类型,如:

描述

class Date
{
    friend ostream& operator<<(ostream& out, const Date& d);
    friend istream& operator>>(istream& in, Date& d);
public:
    Date(int year = 2018, int month = 3, int day = 30)
        :_year(year)
        , _month(month)
        , _day(day)
        {

        }
    void show()
    {
        cout << _year << "-" << _month << "-" << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

ostream& operator<<(ostream& out, const Date& d)
{
    out << d._year << "-" << d._month << "-" << d._day << endl;
    return out;
}
istream& operator>>(istream& in, Date& d)
{
    in >> d._year;
    in >> d._month;
    in >> d._day;
    return in;
}

int main()
{
    Date d;
    cin >> d;
    cout << d << endl;
    system("pause");
    return 0;
}

描述

【静态成员】

class Date
{
public:
    Date(int year = 2018, int month = 3, int day = 30)
        :_year(year)
        , _month(month)
        , _day(day)
    {
        ++_count;
    }

    Date(const Date& d)
        :_year(d._year)
        , _month(d._month)
        , _day(d._day)
    {
        ++_count;
    }

    void show()
    {
        cout << _year << "-" << _month << "-" << _day << endl;
    }
    //静态成员函数没有this指针
    static int GetCount()
    {
        return _count;
    }
private:
    int _year;
    int _month;
    int _day;

    static size_t _count;     //只是声明一个静态变量
};

size_t Date::_count = 0;        //定义静态变量

int main()
{
    Date d;
    cout << d.GetCount() << endl;
    cout << Date::GetCount() << endl;
    system("pause");
    return 0;
}

描述

描述

结论:

  1. 静态成员函数无this指针,不能调用普通成员。
  2. 普通成员通过对象访问(this指针),可以调用静态成员函数。
  3. 成员函数——代码段,静态成员函数——数据段(静态区)

【N种构造拷贝构造的优化情况】

class Date
{
public:
    Date()
    {
        cout << "Date()" << endl;
    }
    Date(const Date& d)
    {
        cout << "Date(const Date& d)" << endl;
    }
    ~Date()
    {
        cout << "~Date()" << endl;
    }

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

void fun1(Date d)
{}

Date fun2()
{
    Date ret;
    return ret;
}

Date fun3()
{
    return Date();
}

int main()
{
    Date d1;
    fun1(d1);
    cout << endl;

    Date();    //也是定义一个对象,是一个临时对象(匿名对象),生命周期只在当前一行
    cout << endl;

    fun1(Date());   //先创建一个匿名对象,再拷贝构造,编译器会优化将其合二为一,只有一个构造
    cout << endl;

    Date d2 = fun2();       //若编译器不优化,则有一个构造,两个拷贝构造。编译器会将return的临时对象的拷贝构造和这里的拷贝构造合二为一
    cout << endl;

    Date d3 = fun3();       //编译器会进行两次优化,先生成一个构造,再对return的临时对象拷贝构造,最后返回来拷贝构造。三个合为一个构造
    cout << endl;

    system("pause");
    return 0;
}

描述

经典面试题:

class AA
{};
AA f (AA a)
{
     return a ;
}
void Test1 ()
{
     AA a1 ;
     a1 = f(a1);
}
void Test2 ()
{
     AA a1 ;
     AA a2 = f(a1);
}

void Test3 ()
{
     AA a1 ;
     AA a2 = f(f(a1));
}
  1. Test1中调用了 2 次AA的拷贝构造函数, 1 次AA的赋值运算符函数的重载。
  2. Test2中调用了 2 次AA的拷贝构造函数, 0 次AA的赋值运算符函数的重载。
  3. Test3中调用了 3 次AA的拷贝构造函数, 0 次AA的赋值运算符函数的重载。

描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值