C++面试基础知识整理(7)

运算符重载

  • 包括友元函数重载和成员函数重载
  • 一元运算符重载
    • -(负号)
    • ++(自增)
  • 二元运算符重载
    • +(加号):第一个参数是*this
    • <<(输出):只能通过友元函数重载,因为第一个参数只能是ostream&,不能是*this
    • [](索引):只能通过成员函数重载,因为第一个参数只能是*this指针。
class Coordinate
{
    // 输出重载
	friend ostream& operator<<(ostream &out, const Coordinate &coor);// 友元函数重载
    
public:
    Coordinate(int x, int y):m_iX(x), m_iY(y){}
    // 负号
    Coordinate& operator-() 
    {
        m_iX=-m_iX;
    	m_iY=-m_iY;
    	return *this;
    }
     // 前置自增
    Coordinate& operator++()
    {
        m_iX++;
        m_iY++;
        return this*;
    }
    // 后置自增
    Coordinate operator++(int)// int是个标识,用于区别于前置自增函数
    {
        Coordinate old(*this);
        m_iX++;
        m_iY++;
        return old;
    }
    // 加号重载
    Coordinate operator+(const Coordinate &coor)
    {
        Coordinate temp(0,0);
        temp.m_iX=this->m_iX+coor.m_iX;
        temp.m_iY=this->m_iY+coor.m_iY;
        return temp;
    }
    // 索引重载
	int operator[](int index)
    {
        if(index==0)
            return m_iX;
        if(index==1)
            return m_iY;
    }
private:
    int m_iX;
    int m_iY;
};
ostream& operator<<(ostream &out, const Coordinate &coor)
{
    out<<coor.m_iX<<","<<coor.m_iY<<endl;
    return out;
}
int main()
{
	Coordinate coor1(3,5);
    Coordinate coor2(4,7);
    Coordinate coor3(0,0);
    -coor1; // coor1.operator-();
    ++coor1;// coor1.operator++();
    coor1++;// coor1.operator++(0);
    coor3=coor1+coor2;// coor1.operator+(coor2);
    cout<<coor1;// operator<<(cout,coor1);
    cout<<coor1[0];// coor1.operator[](0);
    return 0;
}
问题
class CMyString
{
public:
    CMyString(char* pData=nullptr);
    CMyString(const CMyString& str);
    ~CMyString();
private:
    char* m_pData;
}

对上面的类重载赋值(=)运算符

CMyString& CMyString::operator=(const CMyString& str)// 注意传入的参数类型是常量引用,避免调用复制构造函数
{
    // 如果不判断,若是自身则释放掉内存后无法赋值
    if(this==&str)
        return *this;
    
    // 注意释放内存,防止内存泄漏
    delete []m_pData;
    m_pDate=nullptr;
    
    // 注意strlen不包含结束符
    m_pData=new char[strlen(str.m_pData)+1];
    strcpy(m_pData, str.m_pData);
    
    // 返回自身实例的引用,否则不能连续赋值
    return *this;
}

函数模板与类模板

  • 关键字:template、typename、class
  • typename和class等价
使用
// 函数模板
template<class T>// 类型作为参数
T max(T a, T b)
{
    return (a>b)?a:b;
}
template<int size>// 变量作为参数
void display()
{
    cout<<size<<endl;
}

// 类模板
template<class T>
class MyArray
{
public:
    void display(){...}
private:
    T *m_pArr;
}
template<class T>
void MyArray<T>::display()
{
    ...
}
int main()
{
    int ival=max(100,99);
	char cval=max<char>('A','B');
	display<10>();
	MyArray<int> arr;
	arr.display();
}
  • 当函数模板和类模板没有使用时,是不会产生任何代码数据的。只有当使用时才会实例化具体的模板函数和模板类,才会产生真正的代码。

可变参数模板:

泛化之美–C++11可变模板参数的妙用

问题

typename和class的区别

  • 在声明模版参数时,class和typename关键是等价的,可以相互替换。

  • 在涉及“嵌套依赖类型名”(nested dependent type name)的时候,必须用typename关键字去标识。

    template <typename T>
    void print2nd( const T& container)
    {
    	T::const_iterator * x;
    	...
    }
  • 在print2nd这样一个模版函数中,变量x的类型依赖于模版参数T,因此它的具体类型只有在编译时的模版推导过程(template deduction)中才能够被确定。这样的类型称之为“嵌套依赖类型”(nested dependent type name)。

  • 但是很遗憾,编译器并不知道const_iterator是一个类型还是一个静态变量。在默认情况下,C++标准会让编译器会把const_iterator做为一个静态变量处理。

  • typename就会显示告诉编译器T::const_iterator是一个类型,因此这一行的语义就是声明一个嵌套依赖类型的局部变量,而不是一个静态变量乘以x。

    template < typename T>
    void print2nd( const T& container)
    {
    	typename T::const_iterator * x;
    	...
    }
  • 但是在继承列表或者成员初始化列表中的基类初始化时,可以不用typename去标识“嵌套依赖类型”。
    template < typename T>
    class Derived: public Base<T>::Nested //in base class list, no typename
    {
      public :
       explicit Derived(int x)
      : Base<T>::Nested(x) //in member init list, no typename
      {
        typename Base<T>::Nested temp; //nested dependent type, need typename
      }
    };

可调用对象

  • C++中有几种可调用对象:函数,函数指针,lambda表达式,bind创建的对象,以及重载了函数调用符的类。

C++中的各种可调用对象

C/C++:C++可调用对象详解

左值与右值

  • C++( 包括 C) 中所有的表达式和变量要么是左值,要么是右值。通俗的左值的定义就是非临时对象,那些可以在多条语句中使用的对象。所有的变量都满足这个定义,在多条代码中都可以使用,都是左值。

  • 右值是指临时的对象,它们只在当前的语句中有效。

    int i = 0; // i 是左值,0 是临时值,就是右值。在下面的代码中,i 可以被引用,0 就不可以了。
    
    ((i>0) ? i : j) = 1;// 右值也可以出现在赋值表达式的左边,但是不能作为赋值的对象

右值引用、转移构造函数、std::move、精确传递(完美转发):
右值引用与转移语义

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值