C++面向对象编程(无指针篇)以complex类的实现为例

这篇博客通过讲解侯捷老师的C++视频,介绍了面向对象编程的关键概念,包括防卫式声明、初始化、const使用、访问修饰符、函数传参、友元和操作符重载。强调了初始化列表、const的规范使用以及尽量使用引用传递参数。还详细分析了一个complex类的实现,涉及构造函数、成员函数、友元函数以及操作符重载的细节,特别是成员和非成员函数在操作符重载中的应用。

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

C++面向对象编程(无指针篇)以complex类的实现为例

非常推荐大家学习侯捷老师的C++视频!不论是初学者还是有基础的!

看完几集,侯捷老师C++视频的特点是,纲领性地,有重点地讲解C++语言的要点。和网上其他入门视频不同的是,侯捷老师的C++开始就抛出C++重要的概念,比如面向对象、模板、重载、友元等,对于构建C++的知识体系有极大帮助。适合有一定C语言基础的小伙伴们,缺点是对于初学者比较难理解。

对于初学者来说,虽然在学习过程中很困难,很难理解某些概念,但是只要能理解视频中50%的内容,就已经是非常有收获了。高屋建瓴,直奔主题,在刚入门就能培养“大气”的编程习惯和设计思路,这是优秀的程序员(更是设计者)所必须的。

先上重点:

1、防卫式声明一定要采用,规范化表达,避免多头文件重定义的麻烦等。

2、类的规范初始化,能用尽量采用。

3、const的使用:C++中,必须严格规范const,需要加上一定要加上

4、public:公共区域,private:私有区域
建议:数据放在private,函数放在public
但是也有例外:比如单例模式

5、函数传值和传引用:
建议:尽量传引用,但也存在不能传引用的情况

6、friend:友元,可以通过friend取得private中的数据
但是必须慎用:因为会破坏C++封装的特性
相同class的各个objects互为friends

7、操作符重载:成员函数(this)、非成员函数(无this)

(1)所有的成员函数一定带着一个隐藏的this不能在参数列写出来,但是this可以用

(2)有些函数返回一个local object,则不能return by reference,只能return by value。

temp object( 临时对象 ) : typename()

8、class body之外的各种定义(definitions)和使用

9、类与函数的设计注意:
首先,传递参数尽量return by reference;
其次,要考虑操作符的运算对象;
最后,要考虑返回值是否为local object,local object只能return by value。

代码分析

/*complex.h*/

//防卫式声明  guard
#ifndef __COMPLEX__
#define __COMPLEX__

//前置声明  forward declerations
#include <cmath>

class ostream;
class complex;

complex & __doapl(complex *ths, const complex &r);

//template <typename T>		//模板类
//类 - 声明  class declerations
class complex     //class head
{                 //class body   有些函数再次直接定义,另一些在body外定义
public:
    complex (double r = 0, double i = 0)   //构造函数,函数名和类名相同,r, i为默认实参,没有返回类型
        : re(r), im(i)      //initialization list 初始化,初值列
    {   }
    complex &operator += (const complex&);
    double real() const {return re;}   //函数后的const,不改变数据内容
    double imag() const {return im;}

private:
    double re, im;
    friend complex&__doapl (complex* , const complex&);
};

//类 - 定义  class definition
//VS code 中默认会加上下面的,先不管:
complex::complex(/* args */)
{
}
complex::~complex()
{
}

1、防卫式声明一定要采用,规范化表达,避免多头文件重定义的麻烦等

/*complex.h*/
//防卫式声明  guard
#ifndef __COMPLEX__
#define __COMPLEX__

/*
	内容
*/
#endif

2、规范初始化,能用尽量采用:

public:
    complex (double r = 0, double i = 0)   //构造函数,函数名和类名相同,r, i为默认实参,没有返回类型
        : re(r), im(i)      //initialization list 初始化,初值列

下面是不采用初始化的代码:可能会使效率降低,不采用

public:
	complex (double r = 0, double i = 0)
    { re(r); im(i);  }     //赋值语句,放弃了初始化,尽量不采用该方式

3、const的使用:C++中,必须严格规范const,需要加上一定要加上

	double real() const {return re;}   //函数后的const,不改变数据内容
    double imag() const {return im;}

如果不加const, 以下调用会出错:

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

4、public:公共区域,private:私有区域

建议:数据放在private,函数放在public

但是也有例外:比如如下的单例模式

//ctors构造函数被放在private区域,则外界不可创建类
//设计模式   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();       //外界调用

5、函数传值和传引用:

建议:尽量传引用,但也存在不能传引用的情况

//function: pass by value VS pass by reference
class complex
{
public:
    complex(double r = 0, double i = 0)
    : re(r), im(r)
    {   }
    complex& operator += (const complex&);
    double real() const {return re;}
    double imag() const {return im;}
private:
    double re, im;

    friend complex& __doapl(complex *, const complex&);
};

ostream& operator << (ostream& os, const complex& x)
{
    return os << '(' << real(x) << ',' << imag(x) << ')';
}
//临时变量不能返回reference
inline complex& __doapl(complex* ths, const complex& r)
{
    ths->re += r.re;    //第一参数将会被改动
    ths->im += r.im;    //第二参数不会被改动
    return *ths;
}

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

6、friend:友元,可以通过friend取得private中的数据

但是必须慎用:因为会破坏C++封装的特性

相同class的各个objects互为friends

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&);
};

//自由取得friend的private成员
inline complex& __doapl (complex* ths, const complex& r)    
{
    ths->re += r.re;
    ths->im += r.im;
    return *ths;
}
//相同class的各个objects互为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);    //用c2的函数处理c1数据,可以
}

7、操作符重载:成员函数(this)、非成员函数(无this)

//operator overloading (操作符重载-1,成员函数)  this
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)
/*	以 += 操作符为例
	inline complex& complex::operator += (this, const complex& r)
    所有的成员函数一定带着一个隐藏的this
    不能在参数列写出来,但是this可以用
*/
{
    return __doapl(this, r);        //__doapl: do assignment plus
}

inline complex& complex::operator += (const complex& r)
{
    return __doapl(this, r);
}
/*
    传递者无需知道接受者是以reference形式接收   不大理解这句话的意思
*/
/*operator overloading (操作符重载-2,非成员函数)  无this
为了对应client的三种写法,定义三个函数
注意:这些函数都不能return by reference, 因为他们返回的必定是个local object
temp object(临时对象) : typename()
*/
inline complex operator + (const complex& x, const complex& y)
{
    return complex(real(x)+real(y), imag(x)+imag(y));           //c2 = c1 + c2
}

inline complex operator + (const complex& x, double y)
{
    return complex(real(x) + y, imag(x));       //c2 = c1 + 5
}

inline complex operator + (double x, const complex& y)
{
    return complex(x + real(y), imag(y));       //c2 = 7 + c1
}

一元操作符的重载:

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

( cout ) << 操作符的重载实现:

inline complex conj(const complex& x)
{
    return complex(real(x), -imag(x));
}
#include <iostream>
/*	首先,传递参数尽量return by reference
	其次,要考虑操作符的运算对象
	最后,要考虑返回值是否为local object,local object只能return by value
*/
ostream& operator << (ostream& os, const complex& x)
{
    return os << '(' << real(x) << ',' << imag(x) << ')';
}
{
    complex c1(2, 1);
    cout << conj(c1);
    cout << c1 << conj(c1);
}

9、class body之外的定义(definitions)和使用

//class body之外的各种定义(definitions)
inline double imag(const complex& x)
{
    return x.imag();
}
inline double real(const complex& x)
{
    return x.real();
}
//使用
{
    complex c1(2,1);
    cout << imag(c1);
    cout << real(c1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值