类的基本成员函数

一个类包含:构造、析构、拷贝构造、赋值构造、常对象取地址、普通对象取地址基本函数

class Test
{
public:
Test(int data = ) :m_data(data)
{
cout << "构造函数:" << this << endl;
} ~Test()
{
cout << "析构:" << this << endl;
} Test(const Test &t)
{
m_data = t.m_data;
cout << "拷贝构造:" << this << endl;
} Test operator=(const Test &t)
{
if (this != &t)
{
m_data = t.m_data;
}
cout << "赋值构造:" << this << endl; //拷贝赋值
return *this;
} Test* operator&()
{
cout << "普通象取地址:" << this << endl;
return this;
} const Test* operator&()const
{
cout << "常对象取地址:" << this << endl;
return this;
} int GetData() const
{
return m_data;
}
private:
int m_data;
}; int main()
{
Test t1();
Test* t2 = &t1;
const Test t3();
const Test* t4 = &t3;
}

类中的const方法与普通方法

class Test
{
public:
Test(int data=):m_data(data) {}
//相当于void fun(Test* this) const
void fun() const
{
cout << m_data <<endl;
}
//void fun(const Test *const this)
void fun()
{
cout << m_data << endl;
} private:
int m_data;
};

void fun() const和void fun()是可以共存的

如果不加const

void fun()    // <==>void fun(Test* const this)

加了const

void fun() const  // <==> void fun(const Test *const this)

1.因为函数后加了const就封锁了*this 为常量,就不能通过常量更改成员了

2.两个函数的参数的类型不同,所以就可以重载

3.经过调试也可以看出:如果同时有普通方法和常方法,普通对象调用的是普通方法,常量对象调用的是常方法。

4.但是如果没有普通方法,只有常方法,普通对象也可以调用常方法,因为它没有其他选择。反之,如果没有常方法,只有普通方法,常量对象是无法调用普通方法的。因为:普通对象调用常方法,但只是不能修改而已,而常对象要调用普通方法,普通方法是不可以修改的,所以就不成立

总结如下:

1.const对象可以调用非const成员函数吗? //不可以

2.非const对象可以调用const成员函数吗?//可以

3.const成员函数内可以调用其他的非const成员函数吗?//不可以

4.非const成员函数内可以调用其他的const成员函数吗?//可以

ps:即权限缩小的话,都可以

拷贝构造函数

对象初始化对象会调用拷贝构造函数

Test(const Test &t)
{
m_data = t.m_data;
cout << "Copy Create Test Object!" << endl;
}

1.拷贝构造函数Test(const Test &t)的const可以去掉,但前提是用普通对象构造普通对象。如果是常对象就不能构造普通对象,一般为了保护参数,避免函数中修改参数,都会加上const。而且编译器默认就是带有const的拷贝构造函数

2.拷贝构造函数的参数必须要加引用&,如果不加就会无限的调用拷贝构造函数,编译器也不允许。

3.如果成员中没有指针,只是基本的类型,可以用默认的拷贝构造函数

例子

先看一个例子,看看什么时候会调用拷贝构造函数

class Test
{
public:
Test(int data=):m_data(data)
{
cout << "构造函数:"<<this<< endl;
} Test(const Test &t)
{
m_data = t.m_data;
cout << "拷贝构造:" <<this<< endl;
} Test& operator=(Test &t)
{
if (this != &t)
{
m_data = t.m_data;
}
cout << "拷贝赋值:" <<this<< endl;
return *this;
}
~Test()
{
cout << "析构" <<this<< endl;
} int GetData() const
{
return m_data;
}
private:
int m_data;
}; Test fun(Test x) //传递参数调用拷贝构造
{
int value = x.GetData();
Test tmp(value); //调用构造函数
return tmp; //返回tmp时候,必须先创建一个临时对象,然后用tmp去拷贝构造临时对象
} int main()
{
Test t(); //调用构造函数
fun(t);
}

运行结果:

在上面的代码中,返回tmp时候,必须先创建一个临时对象,然后用tmp去拷贝构造临时对象,因为tmp在函数结束时候,就会析构,必须现将其拷贝到一个临时对象中保存,就会调用拷贝构造函数,临时对象和普通对象在同一种空间中,所以它比函数中局部对象更迟析构,函数内的对象,函数运行完,就直接析构了。

现在修改一下:

int main()
{
Test t();
Test t2=fun(t);
}

运行结果:

并没有把上面说到的tmp对象赋值给t2,这时候编译器做了优化,因为有对象需要返回的那个tmp来构造,所以就不需要去构造临时对象,而是直接用tmp构造了t2。

现在修改一下:

Test fun(Test &x)
{
int value = x.GetData();
Test tmp(value);
return tmp;
} int main()
{
Test t();
Test t2=fun(t);
}

运行结果:

可以看到,因为参数引用传递,所以少了一次拷贝构造。

现在修改一下:

Test& fun(Test &x)
{
int value = x.GetData();
Test tmp(value);
return tmp;
} int main()
{
Test t();
Test t2=fun(t);
}

因为现在返回值是引用&,打印出t2的值是个随机值,说明函数作用域内的对象,在运行完就直接析构了,这时候,用这块已经被析构的内存构造的对象当然是个随机值了。

运行结果

现在修改一下:

Test fun(Test &x)
{
int value = x.GetData();
return Test(value);
} int main()
{
Test t();
Test t2=fun(t);
}

运行结果:

经过编译器的优化,编译器直接构造了t2,不会从临时对象向t2的拷贝构造。

现在修改一下:

Test fun(Test &x)
{
int value = x.GetData();
return Test(value);
} int main()
{
Test t();
Test t2;
t2 = fun(t);
}

运行结果:

这时候就会用返回的匿名对象再构造一个临时对象,然后用临时对象来赋值构造t2。

赋值构造函数

Test& operator=(const Test &t)
{
if (this != &t)
{
m_data = t.m_data;
}
return *this;
}

1.const可以去掉,但必须是普通对象赋值构造普通对象,常对象就无法赋值构造普通对象了。一般为了保护参数,避免函数中修改参数对象,都会加上const。而且编译器默认就是带有const的赋值构造函数。

2.参数的引用&可以去掉,那么就会多调用一次拷贝构造函数,效率降低。

3.返回值不是必须的,可以为void,用引用返回值的原因是可以实现链式表达式,提高效率,将返回结果作为另外一个操作符的运算

如:

class{
//...
Test& operator=(const Test& t)
{
if (this != &t)
{
m_data = t.m_data;
}
cout << "赋值构造:" << this << endl;
return *this;
}
///...
} int main()
{
Test t1();
Test t2,t3;
t3=t2 = t1;
cout << t2.GetData() << " " << t3.GetData() << endl;
} //相当于:t3.operator=(t2.operator=(t1))

执行结果是:

4.返回的类型也可以去掉引用&,但是返回就会调用拷贝构造函数

class
{
//...
Test operator=(const Test& t)
{
if (this != &t)
{
m_data = t.m_data;
}
cout << "赋值构造:" << this << endl;
return *this;
}
//...
} int main()
{
Test t1();
Test t2;
t2 = t1;
}

C++类的函数成员的更多相关文章

  1. 类的函数成员之属性property

    属性命名采用Pascal命名方式,每个单词的首字母大写.访问方式与访问类的公共字段类似. /// <summary> /// 字段 /// </summary> private ...

  2. CDocument类的UpdateAllViews()成员函数

    (一)UpdateAllViews() 与 Invalidate()的区别 UpdateAllViews()是在DOC/VIEW结构中,当一个视图的数据改变后,通知所有视图作相应的改变,和重画毫无关系 ...

  3. VC6.0中重载操作符函数无法访问类的私有成员

    整理日: 2015年03月18日 在 C++ 中,操作符(运算符)可以被重载以改写其实际操作.同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类的私有成 ...

  4. C++类的成员函数(在类外定义成员函数、inline成员函数)

    类的成员函数(简称类函数)是函数的一种,它的用法和作用和前面介绍过的函数基本上是一样的,它也有返回值和函数类型,它与一般函数的区别只是:它是属于一个类的成员,出现在类体中.它可以被指定为private ...

  5. C++类的const成员函数、默认的构造函数、复制形参调用函数(转)

    C++类的const成员函数 double Sales_item::avg_price() const { } const关键字表明这是一个const成员函数,它不可以修改Sales_item类的成员 ...

  6. 友元(友元函数、友元类和友元成员函数) C++

    有些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍阻止一般的访问,这是很方便做到的.例如被重载的操作符,如输入或输出操作符,经常需要访问类的私有数据成员. 友元(frend)机制允许一个类将 ...

  7. C++类静态数据成员与类静态成员函数

    from:://http://blog.csdn.net/taina2008/article/details/1684834 把类中的函数都定义成静态函数,这样相当于在编译时就分配了空间,这样不需要实 ...

  8. C++模板编程中只特化模板类的一个成员函数

    模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1.2个成员函数即可.在这种情况下,如果全 ...

  9. c++友元函数、友元类、友成员函数

    友元函数:不是类成员函数,是一个类外的函数,但是可以访问类所有成员. class Point{ public: friend void fun(Point t);//友元函数 private: int ...

随机推荐

  1. 在ASP.NET 中调用 WebService 服务

    一.webservice定义 详见 https://www.cnblogs.com/phoebes/p/8029464.html 二.在ASP.NET MVC 中调用 webservice 1:要调用 ...

  2. Go-结构体,结构体指针和方法

    https://cloud.tencent.com/developer/article/1482382 4.1.结构体 结构体:讲一个或多个变量组合到一起形成新的类型,这个类型就是结构体,结构体是值类 ...

  3. P5168 xtq玩魔塔 [克鲁斯卡尔重构树+带修莫队]

    P5168 xtq玩魔塔 又是码农题- 利用克鲁斯卡尔重构树的性质 我们就可以得出 \(dep\) 值小的,肯定比 \(dep\) 大的值要优. 于是第二问就可以直接 LCA 求出来了- 至于第三问, ...

  4. 《深入理解java虚拟机》读书笔记一——第二章

    第二章 Java内存区域与内存溢出异常 1.运行时数据区域 程序计数器: 当前线程所执行的字节码的行号指示器,用于存放下一条需要运行的指令. 运行速度最快位于处理器内部. 线程私有. 虚拟机栈: 描述 ...

  5. Codeforce 519B - A and B and Compilation Errors

    A and B are preparing themselves for programming contests. B loves to debug his code. But before he ...

  6. 利用MongoDB进行地理坐标查询

    BS的应用在生活中已经非常常见,我们打车,叫外卖,查个地图之类的都会查询附近的相关坐标位置,mongodb提供了原生的二维地图查询,极大地方便了大家的开发. 假定我们有一个定义了位置信息的集合loca ...

  7. web 项目添加 x86 的dll 引用,模块 DLL c:\WINDOWS\system32\inetsrv\aspnetcore.dll 未能加载。

    最近的项目要添加一个 x86 编译的dll, 首先添加引用,编译,报错: 首先判断是 项目中不能添加 x86 的引用,所以把所有的项目都按照 x86 的方式编译一遍,同时对应IIS 的应用池,也修改为 ...

  8. (转)R语言 SVM支持向量机在 R 语言中的实现和使用

    支持向量机是一个相对较新和较先进的机器学习技术,最初提出是为了解决二类分类问题,现在被广泛用于解决多类非线性分类问题和回归问题.继续阅读本文,你将学习到支持向量机如何工作,以及如何利用R语言实现支持向 ...

  9. Git学习笔记-上传一个新的项目到GitHub上

    前提: 已有Github账号,已在Github上建立了仓库,已在Github上配置了SSH,已上传过一些项目到Github上 目标: 目前有一个新的项目,需要上传到github上 我的做法记录: 1. ...

  10. 巨杉Tech|SequoiaDB 巨杉数据库高可用容灾测试

    数据库的高可用是指最大程度地为用户提供服务,避免服务器宕机等故障带来的服务中断.数据库的高可用性不仅仅体现在数据库能否持续提供服务,而且也体现在能否保证数据的一致性. SequoiaDB 巨杉数据库作 ...