《C++语言基础》课程笔记

1.5 内置函数

  • C语言中,提升效率的方法是使用宏定义:#define area(a,b) (a)*(b);
  • C++中,提升效率的方法是使用内置函数:

 

 

1.6 有默认参数的函数

  • 函数声明时为形参指定默认值,例
float (r=6.5);//给定r的默认参数是6.5
  • 函数声明时,形参名可以不写,例

area(float, float = 4.2);

  • 指定默认值的参数必须放在形参列表中的最右端,否则出错,例

void f1(float a, float b=3.0, float c, float d=12.1);//错误

  • 带默认参数的函数仅在声明时设默认参数,而定义时不能设默认参数。

 

 

1.7函数重载

  • 同名同体,但接口不同;
  • 同命不同体,但参数个数不相同;(即重载函数除了参数的类型不一样,参数的个数也可以不一样。)
  • 实现细节不同,同一类的功能时用重载函数
  • 函数的返回值类型不同,但参数个数和类型相同,不是重载
  • 重载函数的参数个数,参数类型,参数顺序必须至少有一个不同,返回值类型可以相同,也可以不同;
  • 函数的重载不要与函数的默认值有冲突;

 

 

1.8函数模板

  • 替代同体重载函数的多次调用;
  • 先进行函数声明:
    • template<typename T>
    • 或template<class T>
  • 类型参数可以不只一个,template<class T1, typename T2>(详见代码)

 

 

1.9 字符串类

 

 

1.10 C++编程环境

  • 建议所存放的文件夹的名称中不要有空格和汉字;
  • 用F10或F11进行调试,查找问题的地方;

 

 

2.1 初见对象

 

 

2.3 基于对象的程序的执行过程

  • 关键字this:前加一个“*”(即*this)表示指向当前对象值的指针。

 

 

2.4 类的成员函数

  • 如果一个类中不包含成员函数,就等同于C语言中的结构体了。体现不出类在面向对象程序设计中的作用。
  • private只能被类内的成员函数调用,类外不能被访问;public,在类的外可以被自由访问;
  • 将需要被外界调用的成员函数指定为public,它们是类的对外接口;有的函数只被本类中的成员函数所调用,以支持其他函数的操作,应将它们指定为private。
  • 成员函数可以访问本类中的任何成员,包括私有的和共有的。

 

 

2.5 对象成员的引用方法

  • void set_data();//成员函数
    int num;//数据成员
  • 面向对象思维解决时:要首先分析设计哪些实体,把它定义成哪些类;要分出数据成员和成员函数,然后实现它的成员函数,最后在main函数里面创建对象,调用它的成员函数,对问题进行实现。

 

 

2.7 类的封装与信息的隐藏

  • 函数外部:关心函数如何使用——函数的参数个数及各自的类型,函数的返回值类型,函数名,函数功能
  • 函数外部:关心函数如何实现——采用什么计算方法,采用什么程序结构,怎样得到数据结果,性能如何保证...
  • 一般对类来讲,将大多数的数据成员设置为私有的;大多数成员函数是私有的。特例,只被自己类内成员函数所调用的成员函数也被设置为私有的。

 

 

2.8 类声明和成员函数定义的分离

  • 类声明放在头文件中;类外的函数定义放在源文件中
  • #include <iostream>//"<>"用的时候会在系统文件中找
    #include "student.h"//""""的话,优先去找当前目录
    一般情况下,自己定义的头文件放在和.cpp同样的文件夹下面

 

 

3.1构造函数

  • structure 与class的区别:structure中的不指定访问权限时,默认是public的;class中不指定访问权限时,默认是private的。
  • 构造函数不具任何数据类型(例如,time前无void等数据类型),不返回任何值。
  • 构造函数的功能由用户定义,用户根据初始化的要求设计函数体和函数参数。
  • 在实际应用中,在构造函数中,对数据成员初始化时,经常用到参数初始化表
     
    class time
    {
    public:
    	time() : hour(0), minute(0), second(0) {};//()中无参数,time是一个无参函数,{}中为空,说明函数体为空
    	time(int h, int m, int s) :hour(h), minute(m), second(s) {};//time()有三个参数,:后为参数初始化
    	...
    }
  • 类外用参数初始化表对数据成员初始化
    time::time(int h, int m, int s) :hour(h), minute(m), second(s) {};
    不是在函数体内(也就是花括号内)对数据成员进行初始化,而是在函数的首部。
  • 一般不在构造函数中加入与初始化无关的东西,以保证程序的清晰性;
  • 在成员函数中,慎用输入输出,尤其是在图形用户界面中。
  • name(s)和strcpy(name, s)都不能出现在首部中用来定义,如果非要这样,需要把char name[20];改成string name;
  • 构造函数重载:同样一个函数,由于参数类型或参数个数不一样,是可以进行重载的。调用时,根据需要可以进行相应的重载。

 

 

3.2 默认构造函数(default constructor)

  • 在调用时不必给出实参的构造函数
  • 调用默认构造函数的格式
    int main()
    {
    	time t1;//不是t1()
    	t1.show_time();
    	return 0;
    }
  • 即使提供了其他的构造函数,提供一个默认构造函数总是对的。通常在默认构造函数中,给成员提供的初始值应该指出该对象是“空”的。

 

3.3带默认参数的构造函数

 

 

3.4析构函数

  • 执行析构函数时,后产生的对象是先被析构的,而先产生的对象后被析构。
  • 析构函数不返回任何值,没有返回类型也没有函数参数
  • 构造函数中,使用new运算符为对象成员动态地分配内存空间;析构函数中使用delete运算符释放分配的空间。
  • 析构函数不能被重载。一个类中,构造函数可以有多个,但是析构函数只能有一个。
  • 析构函数地作业不仅仅局限于释放资源方面。也可以用来进行“用户希望在最后一次使用对象之后后所执行的任何操作。”
  • 一般情况下,类的设计者应该定义析构函数,来指定如何完成“清理”工作。如果用户没有定义析构函数,C++系统会在编译时自动生成一个析构函数。

 

3.5 调用构造函数和析构函数的顺序

 

 

3.6对象数组

  • 结构体是可以定义数组的
    struct A {
    	int num;
    	string name;
    	char gender;
    };
    A a[200];
  • 对象和结构体是除了它访问权限不一样,其实都是一样的。更加喜欢用class描述这样的事情。
    • 对象数组中,每一个元素都是同类中的对象
      class A {
      public:
      	A() {};
      	A(int num, string name, char gender) :n(num),a(name),g(gender){}//n, a, g 是数据成员
      private:
      	int n;
      	string a;
      	char g;
      }
  • 定义类的时候可以是单一的一个的对象
    A c;
    对象在定义的时候可以进行初始化,依靠的是上面的构造函数
    A d(4, "Rose", 'f');
    对象也可以组成数组,有2个元素,每个元素是A类的对象。对象数组里的对象是数组,里面保存的是对象。计算机内存分配2个保存A对象的空间,并且这些空间是连续的。
    A e[2];
    定义对象数组时,同样可以用花括号括起的进行初始化。
    A a[2] = {
    	A(1,"Jack",'m'),
    A(2,"Sally",'f') };

 

 

3.7对象指针

  • 指向对象的指针——可通过对象指针访问对象和对象的成员
    (*pt ).hour或pt->hour//即t1.hour
  • 指向数据成员的指针——

    int *p1;//定义指向数据成员的指针变量
    p1 = &t1.hour;
    cout << *p1 << endl;//通过指向数据成员的指针变量访问数据成员
  • 指向对象成员函数的指针——对于普通函数,占用内存,在程序区不在内存区,名字是首地址;

  • int(*p1)();//后面的括号表示p1是一个函数,括号是空的表示指向无参函数的指针。int表示它的返回值是一个整形。
  • void (Time:: *p2)();//定义指向类成员函数get_time()的指针
  • p2 = &Time::get_time;//指向一个成员函数,后面没有圆括号&Time::get_time;//指向一个成员函数,后面没有圆括号
  • (t.*p2)();//t对象的指向函数的指针,而指向函数的指针是t。t.*p2)();//t对象的指向函数的指针,而指向函数的指针是t。

     

 

3.8this指针

  • 每个对象都可以利用一个自己的特殊指针,this——指向当前对象的指针。
  • this->x//x指的是数据成员
    this->y//y指的是数据成员
    x//指的是形式参数
    y//指的是形式参数

 

 

3.9用const实施保护

  • 常对象中所有对象的值都不能被修改;
  • 常对象中两种等价定义形式——const 类名 对象名(实参列表);类名 const 对象名(实参列表);
  • 常对象必须要有初值——const Test t1 (10,12,11); Test const t1 (10,12,11);
  • 要引用常对象中的数据成员,需将该成员函数声明为const型函数(常成员函数),定义时也需要末尾加上const。
  • 只能通过构造函数的参数初始化表对常数据成员进行初始化
    Time(int h).hour(int h){}//在类内进行定义
    Time::Time(int h).hour(int h){}//在类外进行定义
  • 不能在构造函数中用赋值的方法对常数据成员进行初始化
    Time::Time(int h)(hour = int h; }//错误
  • 不能用成员函数改变常数据成员的值

    void Time::set_time(int h) { hour = h ;}
  • 如果一个对象被声明成常对象,那么将不能调用该对象的非const型的成员函数
    const Time t1(10, 20, 30);
    t1.set_time();//非法
  • 用常成员函数引用常变量

 

 

3.10 常指针和常引用

  • 一个变量的引用就是变量的别名;变量名和内存名都指向同一段内存单元
    int a;//定义a是整型变量
    int &b=a;//声明b是a的引用
    int a=20;
    cout<<b<<endl;
    
  • 函数的形式参数可以是对象的引用
    void fun(Time &t1);
  • 如果不希望在函数中修改实参的值,可以将形参声明为常引用。

    void fun(Time &);//引用的变量名在声明时可以不写
    void doSomething(const Test &r){
    r.setX(5);//非法,t1.setX(5)可以
    r.printXY();
    }
    
    int main(void){
    Test t1(3,5);
    doSomething(t1);
    }
  • 提倡用常引用作为函数参数,好处如下:能保证数据安全,使数据不能被随意修改;调用函数时不必建立实参的拷贝,这样可以提高程序运行效率。

    3.13 对象的动态建立和释放
  • new运算符动态地分配内存后,将返回一个指向新对象的指针的值,用户通过这个地址来访问对象。
    Time *pt1=new Time; //Time对象初始化,调用默认构造函数,初始化的值为(0,0,0)
    Time *pt2; //定义另外一个指针变量
    pt2=new Time(10,20,30);//执行有参数的构造函数
    pt2->show_time();
  • 建立的对象只能通过指针访问;建立对象时执行构造函数;内存不足,出现异常;
  • 不需要由new运算符建立的对象时,用delete运算符释放。

  • 建立指针数组:建立空间小的指针数组,灵活处理占用空间大的对象集合;指针数组保存的是指向对象的数组;

    Sample temp[], *pTemp[];//第一个是对象数组,第二个是指针数组;对象数组给每一个对象分配空间,此时会对每个元素执行构造函数,而指针数组也会分配两个元素的空间,空间保存的是指向对象的指针,而对象目前并没有产生,只有以后用new产生才可以。
    

 

3.14 对象的赋值和复制

  • 通过复制构造函数进行初始化的情况:
    1. 新建立一个对象:利用复制构造函数进行初始化:
      Box box2(box1);
    2. 当函数的参数为类的对象:调用函数时
      void fun(Box b)
      {}
      int main(){
      Box box1(15,14,12);
      fun(box1);
      return 0;
      }

      ,将实参对象完整的传递给形参,通过调用复制构造函数来建立一个实参的拷贝;
    3. 函数的返回值是类的对象:在函数调用完毕,将函数中的对象复制一个临时对象并传给该函数的调用处。
      Box f()
      {
      Box box1(10,20,20);
      return box1;
      }
      int main() {
      Box box2;
      box2=f();
      }

 

 

3.15  深复制

  • char * 专门用于指结尾是“/0”的字符串;
  • 当一个类中有指针数据成员时,必须对该类里所有对象初始化,必须对该类里面所有对象的初始化做深复制。深复制的技术就是先给指针所指的变量分配空间,然后再去做其他的操作。

 

3.17 类模板

在类外定义成员函数

template <class numtype> //template <class 虚拟类型参数>
numtype Compare<numtype>::max() {//函数类型 类模板名 <虚拟类型> :: 函数(函数形参列表)
	return (a < b) ? b : a;
}

 

3.20 函数中的引用

  • 函数中的引用:引用作为形参;引用作为返回值。
  • 当形式参数不是引用的形式时,形式参数向实际参数复制时,同样执行复制构造函数;当形式参数是引用的形式时,不需要实际参数的拷贝,不会产生新的对象,而是直接对实际参数的引用。
  • 返回值为非引用对象时,不会执行复制构造函数,返回值直接取栈中结果。
  • 函数的返回值是类的对象,函数在执行返回调用时,不会调用复制构造函数。(编译器自动进行优化的手段)
  • 返回值为引用对象时,
  • 在某一个地方的引用所对应的空间是有效的空间

 

 

4.1 什么是运算符重载

  • 重载:将同一个名字赋予新的含义。
  • 函数的重载:对于一个函数赋予新的含义,使之实现新的功能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值