C++编译器为类自动生成的函数
来源:互联网 发布:淘宝的电脑主机能买吗 编辑:程序博客网 时间:2024/05/17 07:55
我们可以构建一个空类,
class Empty{};
尽管没有定义任何函数,但我们可以通过以下方式使用这个类:
Empty e1;Empty e2(e1);e2 = e1;
因为当编译器发现你用上述方式使用这个类而却在类声明中没有定义一般构造函数(非复制构造函数)、复制构造函数、赋值操作符重载函数和析构函数时,会自动为其生成这些函数,上面的Empty
类经编译后就对应着下面的类:
class Empty{public: Empty(){...}; Empty(const Empty& rhs){...}; ~Empty(){...}; Empty& operator=(const Empty& rhs){...};};
编译器生成的默认构造函数和析构函数的主要任务是分别调用基类和非静态成员变量的构造和析构函数。生成的复制构造函数和赋值操作符重载函数只是单纯的将源对象的每一个非静态变量拷贝给目标对象。
/****************************************** * simple_class.cpp * * * * C++自动生成的函数 * ******************************************/#include <string>#include <iostream>class Simple{ std::string name; int age;public: void SetName(std::string name) { this->name = name; } void SetAge(int age) { this->age = age; } void Print() { std::cout<<"name="<<name<<","<<"age="<<age<<std::endl; }};int main(){ Simple s1; std::cout<<"s1: "; s1.Print(); std::cout<<"s1: "; s1.SetName("Jim"); s1.SetAge(20); s1.Print(); std::cout<<"s2: "; Simple s2(s1); s2.Print(); Simple s3; s3.SetName("Tom"); s3.SetAge(25); std::cout<<"s3: "; s3.Print(); s3 = s2; std::cout<<"s3: "; s3.Print(); return 0;}
赋值操作符重载函数只有当编译器生成的代码是合法且有意义时才会由编译器自动生成。
/**************************************** * wired_employee.cpp * * * * 不合法的赋值运算符重载函数不会自动生 * * 成 * ****************************************/#include <string>#include <iostream>class WiredEmployee{private: std::string& name; const int age;public: WiredEmployee(std::string& _name, const int& _age) : name(_name),age(_age) { } void Print() { std::cout<<"name="<<name<<","<<age<<std::endl; }};int main(){ std::string name = "Tom"; int age = 20; WiredEmployee a(name,age); std::cout<<"a: "; a.Print(); WiredEmployee b(a); std::cout<<"b: "; b.Print(); std::string name1 = "Jim"; int age1 = 25; WiredEmployee c(name1, age1); std::cout<<"c: "; c.Print(); c = a; return 0;}
从错误中可看出,赋值运算符重载函数没有生成。
若不想使用编译器自动生成的函数,需要自己明确地定义这些函数。
如果不想让用户使用这些函数,可以将其可访问范围设置为private
。然而这样并不完全能够实现这种要求,因为对于友元和成员函数来说,它们仍然是可以访问的。
/*************************************** * forbidden_use.cpp * * * * C++禁止使用成员函数 * ***************************************/#include <iostream>class Test{private: int i;public: Test(int _i) { this->i = _i; } void Use() { /*成员函数中可用*/ std::cout<<"成员函数:"<<std::endl; std::cout<<" a:"; Test a(10); a.Print(); Test b(a); std::cout<<" b:"; b.Print(); Test c(15); std::cout<<" c:"; c.Print(); c = a; std::cout<<" c:"; c.Print(); } void Print() { std::cout<<"i = "<<i<<std::endl; }private: Test(Test& t) { i = t.i; } Test& operator=(const Test& t) { i = t.i; return *this; } friend void UseTest();};/*友元可用*/void UseTest(){ std::cout<<"友元函数: "<<std::endl; Test a(15); std::cout<<" a:"; a.Print(); Test b(a); std::cout<<" b:"; b.Print(); Test c(20); std::cout<<" c:"; c.Print(); c = a; std::cout<<" c:"; c.Print();}int main(){ Test a(20); a.Use(); UseTest(); /* 其他中不可用 Test b(a); Test c(10); c = a; */ return 0;}
更加稳妥的一种方法是将这些函数只声明为private
,而不去实现它们。这样用户使用这些函数的错误将在编译时被发现,而成员函数或友元使用这些函数的错误将在链接时被发现。
/*************************************** * forbidden_use_1.cpp * * * * C++禁止使用成员函数 * ***************************************/#include <iostream>class Test{private: int i;public: Test(int _i) { this->i = _i; } void Use() { /*成员函数中不可用*/ std::cout<<"成员函数:"<<std::endl; std::cout<<" a:"; Test a(10); a.Print(); Test b(a); std::cout<<" b:"; b.Print(); Test c(15); std::cout<<" c:"; c.Print(); c = a; std::cout<<" c:"; c.Print(); } void Print() { std::cout<<"i = "<<i<<std::endl; }private: Test(Test& t); Test& operator=(const Test& t); friend void UseTest();};/*友元不可用*/void UseTest(){ std::cout<<"友元函数: "<<std::endl; Test a(15); std::cout<<" a:"; a.Print(); Test b(a); std::cout<<" b:"; b.Print(); Test c(20); std::cout<<" c:"; c.Print(); c = a; std::cout<<" c:"; c.Print();}int main(){ Test a(20); a.Use(); UseTest(); /* 其他中不可用 Test b(a); Test c(10); c = a; */ return 0;}
还有一种方法是定义一个基类,这个基类的这些函数设置为private
,那么所有继承自该基类的子类就不能被用户,也不能被自己的成员函数和友元使用了。因为无论什么时候使用这些函数,它都会调用父类的相应函数,而父类的这些函数又是private
,就会报错。
/*************************************** * forbidden_use_2.cpp * * * * C++禁止使用成员函数 * ***************************************/#include <iostream>class Uncopyable{protected: Uncopyable(){}; ~Uncopyable(){};private: Uncopyable(const Uncopyable& ); Uncopyable& operator=(const Uncopyable&);};class Test : private Uncopyable{private: int i;public: Test(int _i) { this->i = _i; } void Use() { /*成员函数中不可用*/ std::cout<<"成员函数:"<<std::endl; std::cout<<" a:"; Test a(10); a.Print(); Test b(a); std::cout<<" b:"; b.Print(); Test c(15); std::cout<<" c:"; c.Print(); c = a; std::cout<<" c:"; c.Print(); } void Print() { std::cout<<"i = "<<i<<std::endl; } friend void UseTest();};/*友元不可用*/void UseTest(){ std::cout<<"友元函数: "<<std::endl; Test a(15); std::cout<<" a:"; a.Print(); Test b(a); std::cout<<" b:"; b.Print(); Test c(20); std::cout<<" c:"; c.Print(); c = a; std::cout<<" c:"; c.Print();}int main(){ Test a(20); a.Use(); UseTest(); /* 其他中不可用 Test b(a); Test c(10); c = a; */ return 0;}
下图中只显示了在成员函数Use
中的错误,实际上,当把Use
内的代码注释掉后,友元函数中的错误
就会显示出来
参考文献
- Scott Meyers著,侯捷译. Effective C++中文版. 电子工业出版社. 2012.
0 0
- C++编译器为类自动生成的函数
- Effective C++(6) 如何拒绝编译器的自动生成函数
- C++编译器为类自动生成拷贝构造函数的情况
- EffictiveC++屏蔽编译器自动生成的函数
- 拒绝编译器自动生成的函数
- C++编译器什么时候为我们自动生成拷贝构造函数?
- Effective C++--条款06:如何禁止编译器自动生成函数
- Effective C++:条款06:若不想使用编译器自动生成的函数,就该明确拒绝。
- [Effective C++]条款06 若不想使用编译器自动生成的函数,就该明确拒绝
- <Effective C++>:Item 6 :明确拒绝不想编译器自动生成的函数
- 编译器自动生成的析构函数是非虚函数
- c++基础---之编译器为C++ 空类自动生成的东西有哪些
- Effect C++ 之 编译器自动生成的函数
- Item 5 编译器自动生成和调用的函数
- 编译器自动生成默认构造函数的情况
- C++构造函数和编译器自动生成代码的陷阱
- C++空类编译器自动生成的6个成员函数
- C++空类编译器自动生成的6个成员函数
- LeetCode Contains Duplicate
- Linux复习笔记(四) -- Linux常用命令
- 黑马程序员——Swift学习笔记:流程控制
- UML类图几种关系的总结
- 【线性代数公开课MIT Linear Algebra】 第四课 从矩阵消元到LU分解
- C++编译器为类自动生成的函数
- 【iPhone/iPad】苹果iOS9正式版更新升级及固件刷机教程
- 金星脱口秀有感
- Light OJ 1382 The Queue(组合计数)
- linux安装skynet问题总结
- 响应式网页设计--登陆窗口布局的实现
- leetcode: (141) Linked List Cycle
- openSUSE系统下VirtualBox无法挂载主机USB设备问题的解决
- [枚举最小瓶颈生成树]UVa-1395 - Slim Span(kruskal)