目录 Table of Contents
4 参数传递与返回值
构造函数 ctor 被放在 private 区域
继续看之前的代码
class complex
{
public:
complex (double r = 0, double i = 0)
: re (r), im (i)
{}
complex& operator += (const complex&);
double real() const
{
return re;
}
double imag() const {return im;}
private:
double re, im;
friend complex& __doapl (complex*, const complex&);
};
如果我们把构造函数像这样放到 private 区域会怎么样 ?
class complex
{
public:
complex& operator += (const complex&);
double real() const
{
return re;
}
double imag() const {return im;}
private:
double re, im;
complex (double r = 0, double i = 0)
: re (r), im (i)
{}
friend complex& __doapl (complex*, const complex&);
};
于是我们就无法创建对象了, 因为我们需要构造函数来创建对象, 但是它被放到了私有区域, 外界无法调用, 自然就无法创建对象了
当然也有构造函数被放到私有区域的情况
ctors 放在 private 区
class A
{
public:
static A& getInstance();
setup()
{
//...
}
private:
A();
A(const A& rhs);
//...
};
A& A::getInstance()
{
static A a;
return a;
}
这个是一个设计模式 Singleton, 单子模式, 它就是把构造函数放在了私有区域
我只允许 A 创建一个对象
外界调用要用这种形式才能调用这个函数, 来创建对象
A::getInstance().setup();
const member functions 常量成员函数
class complex
{
public:
complex(double r = 0, double i = 0)
: re(r), im(i)
{}
complex& operator += (const complex&);
double real() const { return re; }
double imag() const { return im; }
private:
double re, im;
friend complex& __doapl(complex*, const complex&);
};
现在我们看这俩函数
double real() const { return re; }
double imag() const { return im; }
这一件事情很多人都会忽略掉, 就是在函数的后面加上 const
, 小括号后面大括号前面.
我们看一下这两个函数的功能, 只是取出来实部和虚部, 并没有改变变量的值
类里面的函数有会改变数据的, 和不改变数据两种函数
不会改变数据内容的函数, 加上 const
, 它的意思就是这个函数不会改变数据;
如果不加的话, 使用者如果这样调用函数
{
const complex c1(2, 1);
cout << c1.real();
cout << c1.imag();
}
编译器就会报错, 因为使用者是把 c1 当作一个常量的, 然后你类里面的函数没写 const
, 就是说这个函数可能会改变数据, 然后编译器就会报错
参数传递 : pass by value vs. pass by reference(to const)
class complex
{
public:
complex(double r = 0, double i = 0)
: re(r), im(i)
{}
complex& operator += (const complex&);
double real() const { return re; }
double imag() const { return im; }
private:
double re, im;
friend complex& __doapl(complex*, const complex&);
};
上面函数的参数有的是直接一个变量, 有的是后面有 &
, 有的是有 const
又有 &
pass by value, 就是这个 value 整个都传进去, 压到栈里面
有时候整个传进去, 会占用很多内存, 太大了. 这时候我们想起来以前 C 语言可以传指针, 现在 C++ 有一个东西像指针但是更漂亮, 这就是 reference 引用.
一个良好的习惯就是最后所有的参数传递都是传引用
如果你希望是传过去很快, 但是不希望你改, 那你就可以在引用前面加 const
, 像下面这样
ostream&
operator << (ostream& os, const complex& x)
{
return os << '(' << real(x) << ',' << imag(x) << ')';
}
返回值传递 : return by value vs return by reference (to const)
reference 除了参数传递, 还有个地方就是返回值传递
函数前面就是返回值类型
尽量用引用的意思是不是所有的情况都可以用它
friend (友元)
朋友可以来拿数据
就是这个朋友可以拿这个类的私有成员
相同 class 的各个 object 互为 friends (友元)
class complex
{
public:
complex (double r = 0, double i = 0)
: re(r), im(i)
{}
int func(const complex& param)
{
return param.re + param.im;
}
private:
double re, im;
};
{
complex c1(2, 1);
complex c2;
c2.func(c1);
}
现在我们增加了这么一个函数 func
, 它接收一个复数, 取得传进来这个复数的实部和虚部, 注意, 这里是传进来另外一个复数, 它竟然可以直接拿私有的实部和虚部, 也没有出现 friend
字眼
有很多个角度可以去解释
相同 class 的各个 object 互为 friends (友元), 这句话可以解释, 你可能会有其它角度来解释, 但这句话可能比较好一些
class body 外的各种定义 (definitions)
-
什么情况下可以 pass by reference
-
什么情况下可以 return by reference
局部变量局部对象, 就不能返回引用, 因为函数一结束, 他们就会随着栈内存释放掉了
do assignment plus __doapl
inline complex&
__doapl(complex* ths, const complex&)
{
ths->re += r.re; // 第一个参数将会被改
ths->im += r.im; // 第二个参数不会被改
return *ths;
}
inline complex&
complex::operator += (const complex& r)
{
return __doapl(this, r);
}
现在的情况是 ths 和 r 相加以后, 结果放到 ths 里面去, 然后 ths 本来就存在嘛, 是传进来的, 所以这里就可以返回引用类型的返回值