C2C++学习笔记(一)

从C到C++(1)

参考资料: 侯捷C++课程.

本文是从C入手C++学习过程中的一些记录. 文中代码均忽略了与对应主题无关的部分, 用 “…” 代替.

输出的变化

首先是基本输入输出的变化. C语言中的输出:

#include <stdio.h>
...
printf("i = %d", i);
...

在C++中输出变为

#include <iostream>
...
cout << "i = " << i << endl;
...

调用方式

调用自己写的头文件和基本库格式上有不同.

#include <iostream>  // 调用基本库
#include "complex.h" // 调用自己写的库

自己写库的规范

要自己写一个Header文件(库)供其他项目调用, 需要注意header文件的行文规范.

#ifndef __COMPLEX__
#define __COMPLEX__

#include <cmath>
class ostream;
class complex;

/// forward declarations, 前置声明
complex&
__doapl (complex* ths, const complex& r);

/// class declarations, 类声明
class complex // class head
// class body
{
    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&);
}

/// class definition, 类定义
complex::function ...

#endif

首先是防卫式声明. 第一句, 判断如果不曾定义过complex, 就把它定义出来, 按照后面文件主体的代码定义. 这样, 第二次进入这个文件, 就发现这个complex已经被定义过, 就不会再进入文件主体.

在主体部分写类的具体内容, 包含前置声明, 类声明, 类的定义.

类的模板 class template

在上面的类具体内容中限定了复数的实部虚部都为double类型, 但实际上我们可能用到float类型, int类型的复数, 难道要为了类型的改变重写一遍吗? 那太浪费时间了. C++提供了类模板工具, 我们可以不把类型定义死.

template <typename T> // 告诉编译器, 用T指代未定的类型名称
class complex // class head
// class body
{
    public:
    complex(T r = 0, T i = 0)
    : re(r), im(i)
    { }
    complex& operator += (const complex&); 
    T real () const { return re;}
    T imag () const { return im;}

    private:
    T re, im;

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

{
    complex<double> c1(2.5, 1.5); // 告诉编译器未定类型名称T绑定为double
    complex<int>    c2(2, 6);
}

类的声明

访问级别

  1. 一般来说, 数据是作为private的, 只有类自己能看到, 不让外界轻易访问和修改.
  2. 要给外界使用的函数, 就放在public级别.
  3. 并不一定要把所有的public和private集中到两段内, 可以随用随定义.
  4. 尽量, 我们要让数据private, 所以数据的读写要另外写配套的函数放在public里面.

inline函数(内联函数)

  1. 内联函数会快会好, 但太复杂的函数, 编译器做不到inline.
  2. 一个函数是否变为inline函数, 我们是不知道的.
  3. 可以把构造函数, 数据读写函数作为内联函数.
  4. 在函数定义前面加上inline表示希望编译器把它作为内联函数(最后能不能成还得看编译器)
inline double imag(const complex& x)
{
    return x.imag();
}

构造函数

  1. 构造函数是用来创建对象的. 它的名字和类的名字是相同的.
  2. 构造函数没有返回值, 不需要有.
  3. 可以用赋值的方式: re = r 写构造函数, 但是我们最好使用初值列的语法来写: re(r)
complex (double r = 0, double i = 0)
: re (r), im(i)
...
complex c1(2.5, 1.5);
complex c2();
complex 
  1. 一个变量的数值设定, 有两个阶段, 一是初始化, 二是赋值. 初始化就是构造函数的初值列所做的事情, 如果用赋值的方式来写, 效率会低一些.
  2. 不可能调用构造函数, 只需要在初始化一个变量的时候直接用即可.
  3. 不带指针的类一般不需要析构函数(什么是析构函数?).
  4. 是可以有多个同名函数的(但实际在编译器之后是不同名的). 这是重载(overloading). 只要参数不同. 所以常常会写多个同名的构造函数, 应对不同的情况.
  5. 如果已经有一个带默认参数的构造函数了, 这个时候再去写一个不需要参数的构造函数, 是会带来混乱的, 这种情况是不合法的.
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值