对教程中的例子,稍加修改,添加了友元类的使用。
#include <iostream> using namespace std; class Box { double width; public: friend void printWidth(Box box); friend class BigBox; void setWidth(double wid); }; class BigBox { public : void Print(int width, Box &box) { // BigBox是Box的友元类,它可以直接访问Box类的任何成员 box.setWidth(width); cout << "Width of box : " << box.width << endl; } }; // 成员函数定义 void Box::setWidth(double wid) { width = wid; } // 请注意:printWidth() 不是任何类的成员函数 void printWidth(Box box) { /* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */ cout << "Width of box : " << box.width << endl; } // 程序的主函数 int main() { Box box; BigBox big; // 使用成员函数设置宽度 box.setWidth(10.0); // 使用友元函数输出宽度 printWidth(box); // 使用友元类中的方法设置宽度 big.Print(20, box); getchar(); return 0; }
友元函数的使用
因为友元函数没有this指针,则参数要有三种情况:
要访问非static成员时,需要对象做参数;
要访问static成员或全局变量时,则不需要对象做参数;
如果做参数的对象是全局对象,则不需要对象做参数.
可以直接调用友元函数,不需要通过对象或指针
实例代码:
class INTEGER { friend void Print(const INTEGER& obj);//声明友元函数 }; void Print(const INTEGER& obj) { //函数体 } void main() { INTEGER obj; Print(obj);//直接调用 }
几个原则:
C++ primer p406 :拷贝构造函数是一种特殊的构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显示使用拷贝构造函数。当该类型的对象传递给函数或从函数返回该类型的对象时,将隐式调用拷贝构造函数。
C++支持两种初始化形式:
拷贝初始化 int a = 5; 和直接初始化 int a(5); 对于其他类型没有什么区别,对于类类型直接初始化直接调用实参匹配的构造函数,拷贝初始化总是调用拷贝构造函数,也就是说:
A x(2); //直接初始化,调用构造函数 A y = x; //拷贝初始化,调用拷贝构造函数
必须定义拷贝构造函数的情况:
只包含类类型成员或内置类型(但不是指针类型)成员的类,无须显式地定义拷贝构造函数也可以拷贝;有的类有一个数据成员是指针,或者是有成员表示在构造函数中分配的其他资源,这两种情况下都必须定义拷贝构造函数。
什么情况使用拷贝构造函数:
类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:
在C++中,下面三种对象需要调用拷贝构造函数!
1. 对象以值传递的方式传入函数参数
class CExample { private: int a; public: //构造函数 CExample(int b) { a = b; cout<<"creat: "<<a<<endl; } //拷贝构造 CExample(const CExample& C) { a = C.a; cout<<"copy"<<endl; } //析构函数 ~CExample() { cout<< "delete: "<<a<<endl; } void Show () { cout<<a<<endl; } }; //全局函数,传入的是对象 void g_Fun(CExample C) { cout<<"test"<<endl; } int main() { CExample test(1); //传入对象 g_Fun(test); return 0; }
调用g_Fun()时,会产生以下几个重要步骤:
初始化顺序最好要按照变量在类声明的顺序一致,否则会出现下面的特殊情况:
#include<iostream> using namespace std; class Student1 { public: int a; int b; void fprint(){ cout<<" a = "<<a<<" "<<"b = "<<b<<endl; } Student1(int i):b(i),a(b){ } //异常顺序:发现a的值为0 b的值为2 说明初始化仅仅对b有效果,对a没有起到初始化作用 // Student1(int i):a(i),b(a){ } //正常顺序:发现a = b = 2 说明两个变量都是初始化了的 Student1() // 无参构造函数 { cout << "默认构造函数Student1" << endl ; } Student1(const Student1& t1) // 拷贝构造函数 { cout << "拷贝构造函数Student1" << endl ; this->a = t1.a ; } Student1& operator = (const Student1& t1) // 赋值运算符 { cout << "赋值函数Student1" << endl ; this->a = t1.a ; return *this; } }; class Student2 { public: Student1 test ; Student2(Student1 &t1){ test = t1 ; } // Student2(Student1 &t1):test(t1){} }; int main() { Student1 A(2); //进入默认构造函数 Student2 B(A); //进入拷贝构造函数 A.fprint(); //输出前面初始化的结果 }
两种不同的初始化方法结果如下:
异常初始化顺序:
正常初始化顺序:
由上面的例子可知,初始化列表的顺序要跟你在类声明的顺序要一致。否则像上面的那种特殊情况,有些变量就不会被初始化。经过测试发现,类中变量为下面的情况也是能够正常初始化的:也就是说,只要成员变量的初始化不依赖其他成员变量,即使顺序不同也能正确的初始化。
int a; int b; int c; Student1(int i):b(i),a(i),c(i){} main: Student1 A(2); A.fprint();
结果:
int a; int b; int c; Student1(int i,int j,int k):b(i),a(j),c(k){} main: Student1 A(2,3,4); A.fprint();
感谢您的支持,我会继续努力的!
支付宝扫一扫,即可进行扫码打赏哦
2009cpp-friend-functions
对教程中的例子,稍加修改,添加了友元类的使用。
2008cpp-friend-functions
友元函数的使用
因为友元函数没有this指针,则参数要有三种情况:
要访问非static成员时,需要对象做参数;
要访问static成员或全局变量时,则不需要对象做参数;
如果做参数的对象是全局对象,则不需要对象做参数.
可以直接调用友元函数,不需要通过对象或指针
实例代码:
2007cpp-copy-constructor
拷贝构造函数
几个原则:
C++ primer p406 :拷贝构造函数是一种特殊的构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显示使用拷贝构造函数。当该类型的对象传递给函数或从函数返回该类型的对象时,将隐式调用拷贝构造函数。
C++支持两种初始化形式:
拷贝初始化 int a = 5; 和直接初始化 int a(5); 对于其他类型没有什么区别,对于类类型直接初始化直接调用实参匹配的构造函数,拷贝初始化总是调用拷贝构造函数,也就是说:
必须定义拷贝构造函数的情况:
只包含类类型成员或内置类型(但不是指针类型)成员的类,无须显式地定义拷贝构造函数也可以拷贝;有的类有一个数据成员是指针,或者是有成员表示在构造函数中分配的其他资源,这两种情况下都必须定义拷贝构造函数。
什么情况使用拷贝构造函数:
类的对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:
2006cpp-copy-constructor
拷贝构造函数的调用时机
在C++中,下面三种对象需要调用拷贝构造函数!
1. 对象以值传递的方式传入函数参数
调用g_Fun()时,会产生以下几个重要步骤:
2005cpp-constructor-destructor
初始化顺序最好要按照变量在类声明的顺序一致,否则会出现下面的特殊情况:
两种不同的初始化方法结果如下:
异常初始化顺序:
正常初始化顺序:
由上面的例子可知,初始化列表的顺序要跟你在类声明的顺序要一致。否则像上面的那种特殊情况,有些变量就不会被初始化。经过测试发现,类中变量为下面的情况也是能够正常初始化的:也就是说,只要成员变量的初始化不依赖其他成员变量,即使顺序不同也能正确的初始化。
结果: