class without pointer members(s)

以下主要是关于候捷老师的c++面向对象开发的笔记。通过实现complex的基本功能,可以实现一个单一的不带指针的类的声明和定义,对面向对象的思想有了初步的了解。

头文件的基本结构

// 防卫式声明
#ifndef _COMPLEX_   
#define _COMPLEX_   
// 前置声明
...
// 类 - 声明
...
// 类 - 定义
...
// 非成员函数的定义, 全局函数
#endif  // !_COMPLEX_

Header的防卫式声明

#ifndef _COMPLEX_   // 第一次include时定义
#define _COMPLEX_   // 第二次则跳过

#endif  // !_COMPLEX_

类的声明

class complex {
public:    // 希望被外界使用的函数
	complex(double r = 0, double i = 0) : re(r), im(i) {}
	complex& operator += (const complex&);
	double real() const { return re; }  // 函数如果直接在class body内定义完成, 自动成为inline候选人
	double imag() const { return im; }
private:   // 只有class里可以看到, 希望将数据封装
	double re, im;
	friend complex& _doapl(complex*, const complex&);

};

public与private

希望被外界使用的函数应放在public内声明;不希望被外界“看见”的函数和变量应在private内声明,只有在class里可以看见,起到封装的作用。

{   // public和private成员access level的不同
	complex c1(2, 1);
	// ×  
	// cout << c1.re << c1.im;
	// √
	cout << c1.real() << c1.imag();
}

inline函数

将函数声明为inline,表示要求编译器在每个函数调用点上,将函数的内容展开。inline仅仅是一种请求,决定权在编译器手上。

默认参数,default argument

关于默认参数的设置有两个不直观的规则:

  1. 默认值的解析是从最右边开始的,具有默认值的参数应在右边;
  2. 默认值只能指定一次,却不能在声明和定义两处都指定。

构造函数, ctor

构造函数就是用来初始化对象的成员变量的,有以下特点:

  1. ctor的名字一定要与class的名字相同
  2. ctor没有返回类型
  3. 创建对象时,会自动调用ctor
  4. ctor可以有很多个 ,可以overload
比较以下两种构造方式的差异
// 1
complex (double r = 0, double i = 0) : re(r), im(r) {}
// 2
complex (double r = 0, double i = 0) { re = r; im = i; }

构造方式1中的变量经过了初始化的过程,而方式2意味着变量放弃了初始化阶段选择直接赋值,这样做的效率比较差。编写代码时应该采用前者,是一种大气、正规的写法。

思考这样一种构造方式
// ctor
complex () : re(0), im(0) {}
// 实例化对象
complex c1;
complex c2();

运行程序会报错,原因在于构造函数没有提高默认实参,default argument

把ctor放在private区域

这样就意味着不能被外界调用,也就无法完成初始化。

// 下面的实例化均会报错
complex c1(2, 1);
complex c2;

常量成员函数,const member functions

在成员函数声明之后加上const,就成了常量成员函数,确保函数内变量不会被修改。const对象只能调用const成员函数。在设计class时,如果函数内变量不会被修改,最好加上一个const。

// 1
complex c1(2, 1);
cout << c1.real() << c1.imag();
// 2
const complex c2(2, 1);
cout << c2.real() << c2.imag();

参数传递

传值就是说把数据复制一份再传递, 速度更慢。
引用就是变量的别名,传引用不会涉及再分配内存,直接对原始数据进行处理,速度更快。
除少部分情况外,最好所有的参数传递都采用传引用方式。

引用和指针

指针可能不会指向某个实际对象,所以在使用指针时必须要判断是否为null。引用就是别名,不会分配内存,肯定会代表某个对象,不需要做此检查。

返回值传递

可以把传递理解为赋值,返回值传递即为用返回值赋给返回类型对应的对象。
由于函数内定义的对象只存在于函数执行期间,如果将这些局部对象的地址返回,就会导致运行错误。
提供者不需要知道接受者是否以reference形式接收
思考下面的返回值类型能否为void?

inline complex& _doapl(complex* ths, const complex &r){
	...
	return *ths;
}
inline complex& complex::operator += (const complex &r){
	return _doapl(this, r);
}

考虑到连串赋值操作时,这里的返回值类型一定要为complex&。

this指针

所有的成员函数均含有一个隐藏参数,this pointer,指向调用者本身。
this指针不能在参数列表中写出,在成员函数内部可以直接使用

友元,friend

友元提供了一种普通函数访问另一个类中的私有成员的方法
相同class的各个成员互为友元

操作符重载,operator overloading

编译器根据参数类型和数量进行判断,而不是返回类型

inline complex operator + (const complex& x, const complex& y)   // 非成员函数, 全局global
{
	return complex(x.real() + y.real(),
		x.imag() + y.imag());
}

inline complex operator + (const complex& x, double y)
{
	return complex(x.real() + y, x.imag());
}

inline complex operator + (double x, const complex& y)
{
	return complex(x + y.real(), y.imag());
}

complex源码

#pragma once

#ifndef _COMPLEX_
#define _COMPLEX_


#include <math.h>

class complex;
complex& _doapl(complex* ths, const complex& r);


class complex {
public:    // 希望被外界使用的函数
	complex(double r = 0, double i = 0) : re(r), im(i) {}
	complex& operator += (const complex&);
	double real() const { return re; }  // 函数如果直接在class body内定义完成, 自动成为inline候选人
	double imag() const { return im; }
private:   // 只有class里可以看到, 希望将数据封装
	double re, im;
	friend complex& _doapl(complex*, const complex&);
};

// 函数定义
inline complex& _doapl(complex* ths, const complex& r) 
{
	ths->re += r.re;
	ths->im += r.im;
	return *ths;
}

inline complex& complex::operator += (const complex& r)
{
	return _doapl(this, r);
}

inline double imag(const complex& x)
{
	return x.imag();
}

inline double real(const complex& x)
{
	return x.real();
}



inline complex operator + (const complex& x, const complex& y)   // 非成员函数, 全局global
{
	return complex(x.real() + y.real(),
		x.imag() + y.imag());
}

inline complex operator + (const complex& x, double y)
{
	return complex(x.real() + y, x.imag());
}

inline complex operator + (double x, const complex& y)
{
	return complex(x + y.real(), y.imag());
}

inline complex operator - (const complex& x, const complex& y)
{
	return complex(real(x) - real(y), imag(x) - imag(y));
}

inline complex operator - (const complex& x, double y)
{
	return complex(real(x) - y, imag(x));
}

inline complex operator - (double x, const complex& y)
{
	return complex(x - real(y), imag(y));
}

inline complex operator + (const complex& x)
{
	return x;
}

inline complex operator - (const complex& x)
{
	return complex(-real(x), -imag(x));
}

inline bool operator == (const complex& x, const complex& y)
{
	return real(x) == real(y) && imag(x) == imag(y);
}

inline bool operator == (const complex& x, double y)
{
	return real(x) == y && imag(x) == 0;
}

inline bool operator == (double x, const complex& y)
{
	return x == real(y) && y == 0;
}

inline bool operator != (const complex& x, const complex& y)
{
	return real(x) != real(y) || imag(x) != imag(y);
}

inline bool operator != (const complex& x, double y)
{
	return real(x) != y || imag(x) != 0;
}

inline bool operator != (double x, const complex& y)
{
	return x != real(y) || imag(y) != 0;
}

inline complex conj(const complex& x)
{
	return complex(real(x), -imag(x));
}

inline double modulus(const complex& x)
{
	return sqrt(real(x) * real(x) + imag(x) * imag(x));
}



#endif // !_COMPLEX_

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值