c++面向对象高级课程 1(侯捷)

本文详细讲解了C++程序中的关键概念,包括C++文件类型、头文件规范、内联函数、构造函数(单例模式)、常量成员函数、友元机制以及操作符重载(包括成员函数和非成员函数)。通过实例演示了如何正确使用这些技术来编写高效和可维护的代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.C++程序代码的基本形式

1.1 C++文件类型

  • . h文件:
    • 头文件:声明;
    • 标准库.
  • .cpp
    • 主体

1.2头文件的正规写法

  • 防卫式声明
#ifndef _COMPLEX_    //如果之前没有引用,第一次引用顺利往下
#define _COMPLEX_   //定义 _COMPLEX_
...
#endif

1.3内联函数 inline

函数在类的本体里定义,就形成inline .很快很好,但是函数太复杂无法inline。
如下,real()和imag都在本体里定义,为inline,

class complex	//class head
{				//class body
public:
	comlpex(double r=0, double i=0)
		: re (r), im(i)
	{}
	complex& operator += (const complex&);
	double real () const{ return re; }//此两函数有大括号{},即在此处定义
	double imag () const{ return im; }
pravite:
	double re, im;

	friend complex&_doapl(copmlex*, const complex&);
};

{
	complex c1(2, 1);
	complex c2;
	...
}

还可以使用关键字定义

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

1.4 访问级别

public :一般是函数,外界需要使用

private:一般是数据部分
还有protected 待续
使用:

正确,使用函数
{
	complex c1(1 ,2);//
	cout<<c1.real();
	cout<<c1.imag();
}
错误,数据是private
{
	complex c1(1 ,2);//
	cout<<c1.re;
	cout<<c1.im;
}

1.5构造函数

1.5.1想要创建一个对象,则自动调用

{
	complex c1(2,1);
	complex c2;//使用构造函数的默认值
	complex* p = new complex(4);
}

1.5.2语法:

comlpex(double r=0, double i=0)
	: re (r), im(i)//初始化方法,仅构造函数可以使用,本体不再使用赋值的方法
{}
  • 构造函数可以重载
    但是以下为错误调用:
complex(double r=0, double i=0)	: re (r), im(i)
complex() : re(0) ,im(0);
...
{
	complex c1;
	complex c2();
}
//此时,c1为无参数,两个构造函数均可以调用,出现错误,因为第一个已经有默认值,两者冲突

1.5.3构造函数priave形式–单例 singleton

class A
{
public : 
	static A& getInstance();
	setup(){...};
private:
	A();
	A(const A&rhs);
}

A& A::getInstance()
{
	static A a;
	return a;
}

单例外界只可以使用一份,如果想要调用A :: getInstance ().setup();

1.6常量成员函数与参数传递和返回值传递

class里的函数,有会改变数据内容的和不改变数据内容的,如果是不改变的,加上const,如下,仅仅是取数据。不改变double re,im;

	double real () const{ return re; }//此两函数有大括号{},即在此处定义
	double imag () const{ return im; }

如果上代码忘记写const,但是构造的变量却使用的const const complex c1(1,2)则矛盾
构造时数据不可以改但是函数部分没了const又表名可以改,bug了,不可以使用c1.real() (没有const的版本);

pass by value、pass by reference和pass by reference to const

  1. pass by value:传递数值,整个数值,所有内容都传递出去,字节数相同,不建议使用。
complex( double r=0	,double i=0): re(r), im(i) { }
  1. pass by reference:传递引用,引用的底部就相当于一个指针,传递速度很快。
ostream& 
operator << (ostream& os,const complex& x)
{
	return os << '('<<real(x)<<","<<imag(x)<<')';
}
  1. pass by reference to const:传递的引用不可以被修改
complex& operator += ( const complex& );

- 返回值也尽可能的return by reference,但是有情况不可以使用
比如做加法,c1 + c2,结果可以用两种方式保存, c1 += c2,直接放进c1里,另外一种是在函数中新建一个变量, c3 = c1 + c2,后者不可以返回引用。因为C3是一个Local型,函数结束则释放,不可以再传引用

传输者无需知道接受者以reference形式接收
例如在

{
	complex c1(2,1);
	complex c2(5);
	c2 += c1;
}
inline complex&
_doapl(complex* ths,const complex& r)
{
	ths -> re += r.re;
	ths -> im += r.im;
	return *ths;
}

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

按理来说,__doapl执行完返回是一个指针型,但是内联函数operator却是返回 complex&型,不冲突,在c2 += c1返回什么值不重要,接收就行,返回void也正确。
但是如果为c3 += c2 += c1 先将c1,c2相加,值返回,再加到c3上,这里就必须返回

1.7友元

friend  complex& _doapl(complex*,const complex&)

这样调用class中的private数据可以直接使用

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

相同class的各个object互为友元

class complex
{
public:
    complex( double r=0	,double i=0): re(r), im(i) { }
	int func(const complex& param ){return param.re + param.im ;}
	//很神奇,param可以直接访问私有的re 和 im	
}

使用

{
	complex c1(2, 1);
	complex c2;
	c2.func(c1);
}

1.8操作符重载

1.8.1成员函数重载 1 this

先看下面的代码。这个 c2 += c1的本质要理解。 += 本质上是一个函数,把 += 作用在左边的c2

{
	complex c1(2 ,1);
	complex c2(5);

	c2 += c1;
}

那么既然是函数,我也可以自己定义

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

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

在上面重载中,隐含了一个this,也就是操作符作用的那个c2 ,完整来说上面应该是

complex :: operator += (this ,const complex& r)//不能写this,但是确实存在

+= 是把右边加到左边,右边就是r ,左边就是this,然后一步一步返回引用。完成 +=操作

任何一个成员函数有一个隐藏的this,一个指针,指向调用者,谁调用,就指向谁

1.8.2 非成员函数重载 2 无this

没有this pointer,函数作为全局函数,如果有多种情况,则需要多情况列出使用。
比如

	complex c1(2 ,1);
	complex c2;	
c2 = c1 + c2;
对应的:
inline complex 
operator + (const complex& x,const complex& y)
{
	return complex(real(x) + real(y) , imag(x) + imag(y));
}
c2 = c1 + 5;
对应的:
inline complex 
operator + (const complex& x,double y)
{
	return complex(real(x) + y , imag(x));
}

以上均为return by value,而且不可以return by reference 。与 c2 += c1不同,是把c1加到c2上,返回引用,这里是吧c2 + c1,没有返回给c2 或者c1任何一个,也就是说,这个结果需要在函数里重新定义一个值,把结果给上去,但是,这是个local value ,离开函数就死亡,所以不能返回引用。

那么问题又来了,说好的在函数里创建一个值,接收结果,那值呢?这里使用的临时对象

1.8.3临时对象 typename()

complex(real(x) + real(y) , imag(x) + imag(y))

complex是类名,创建一个临时对象,把结果给上去,这种赋值类似于 int(5)

complex();
complex(4,5);
//都是临时对象,下一行就不见了

再来看一个例子

inline complex
{
	operator - (const complex& x)
	{
		return complex(real(x),-imag(x));
	}
}
这里,需要把负值返回,所以又是一个临时变量

1.8.4 << 操作符重载

如何输出复数?

{
	complex c1(2, 1);
	cout << conj(c1);
}

<< 操作符,把右边的传到左边 也就是把conj(c1) / **共轭复数 * / 传给 cout,这种操作符只能写成全局的非成员函数。操作符两个参数第一个是cout,第二是是conj(c1)

#include <iostream.h>
ostream&
operator << (ostream& os , const complex& x)
{
	return os << '(' << real(x)<<','<<imag(x)<<')';
}1)os部分可不可以写 const   不可以,表面上os没有更改,实际return中
把每个值都给了os
(2)单看cout<<conj(c1).输出后并不在乎返回值,所以此时返回void没错
(3)但是 cout<<c1<<conj(c1);就不行,右边的值返回,传给c1,c1再返回给cout
所以最后返回类型ostream&

总结

如何写好一个类?
(1)构造函数中 complex(double r=0, double i=0) : re (r), im(i) {}会用
(2)考虑函数该不该加 const
(3)函数参数和返回值 考虑 by reference
(4)数据尽可能在private ,函数绝大部分在public

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值