从C到C++
1.C++的编译过程
编译工具:g++。
步骤:
1.预处理:处理带#号的东西:头文件,宏定义,选择编译
g++ -E *.c -o demo.i
2.编译:语法错误检查
g++ -S *.i -o demo.s
3汇编:将汇编语言转化为二进制语言,生成不可运行的二进制文件。
g++ -c *.s -o demo.o
4链接:将库代码、启动代码 加载到目标文件成为最终的执行程序。
g++ *.o -o demo
2.面向过程和面向对象
1.面向过程:c
面向过程设计:
程序 = 数据结构 + 算法
2.面向对象:c++
面向对象设计:
对象 = 数据结构 + 算法
程序 = (对象 + 对象 + …)+ 对象间通讯机制
3.c和c++的差异具体表现
1.常变量
1.在变量的基础上加const限定: 存储单元中的值不允许变化。因此常变量又称为只读变量(read-only-variable)。
2.注意: const 可以修饰类方法,表示方法不能 修改 类对象
1. ```c++
eg:
void primsg() const //表示 primsg 是const 修饰的方法 ,不能修改类对象
{
}
```2. 注意区别用#define命令定义的符号常量和用const定义的常变量
2.强制类型转换
C语言强制类型转换的一般形式:(类型名)(表达式)
示例:(double)a (将a转换成double类型)
C++还增加了以下形式: 类型名(表达式)
示例: int(x); int (x+y);
3.变量的引用
对一个数据可以使用“引用”,这是C++对C的一个重要扩充,引用是一种新的变量类型,它的作用是为一个变量起一个别名。
不能同时引用两个变量
int a=6;
int b=7;
int &c = a;
int &c = b; //不可以
C中函数之间的参数传递方式有:值传递方式、地址传递方式;C++增加了函数参数引用。
4.函数重载
C++允许用同一函数名定义多个函数,这些函数的参数个数和参数类型不同。这就是函数的重载(function overloading)。即对一个函数名重新赋予它新的含义,使一个函数名可以多用。
例如:
int fun( int x)
{
}
int fun(int x, int y)
{
}
double fun(int x, int y, double z)
{
}
5.结构体
C++语法中相对C语法增加了访问权限的概念,有三种:public、private及protected,默认是public。
public:公共成员,表示可以通过结构体变量对象直接访问到成员
private :私有成员,表示仅结构体成员函数可以使用的成员
protected:保护成员,表示被继承的派生对象可以访问使用的成员
由于增加访问权限,结构体变量就得增加构造函数的概念和this指针,不然成员函数访问成员数据就是问题。
//定义结构体
struct demo{
public: //公有访问权限:表示结构体内外部 都可以通过 结构体变量访问
int getx() //成员方法
{
return x;
}
void setx(int val) // 成员方法
{
x = val;
}
void sety(int val) // 成员方法
{
y = val;
}
int y ; //公有成员 y
protected: //保护访问权限 由 派生的对象 可以访问
private: //私有 访问权限 只能结构体 内部访问(成员方法)
int x;
};
int main()
{
struct demo obj;
// obj.x = 123; // error:x 是 private成员, 不可以通过 外部 变量访问 只能通过 内部访问
obj.setx(666);
printf("%d\n", obj.getx());
//printf("%d\n", obj.x) ; //不允许 直接访问 私有成员 x
obj.sety(777) ;
printf("%d\n", obj.y); //允许直接访问 公有成员 y
return 0;
}
6.名字空间
声明:namespace 空间名
使用名字空间:
1.using namespace 空间名;
2. 空间名::prnmsg();
7.动态内存
c:
malloc free :函数
c++
new delete : 运算符
int * p = new int ; delete p
chat *p = new char [1024]; delete [] p
8.标准输入输出流
1.标准输出流
#include
using namespace std;
cout:
cout << 表达式<<表达式2<< … << endl;
2.标准输入流
#include
using namespace std;
cin:
cin>>变量1>>变量2>>…
4.类和对象
1.OPP思想
三个基本特征:
封装:使代码模块化
继承:扩展已经存在的代码模块(类)为了让代码重用
多态:实现接口的重用
2.类和对象
类是对象的抽象,而对象是类的具体实例(instance)。
类是抽象的,不占用内存,而对象是具体的,占用存储空间。在一开始时弄清对象和类的关系是十分重要的。
1.定义类 class
class 类名
{
private:
私有的数据和成员函数;
public:
公用的数据和成员函数;
protected:
保护的数据和成员函数
};
2.构造函数和析构函数
1)构造函数
是一种特殊的成员函数,与其他成员函数不同:
A、不需要用户来调用它也不能调用,而是在建立对象时自动执行。
B、构造函数的名字必须与类名同名,而不能由用户任意命名,以便编译系统能识别它并把它作为构造函数处理。
C、没有返回值。
D、构造函数的功能是由用户定义的,用户根据初始化的要求设计函数体和函数参数。
E、如果用户不设计,则编译器自动生成一个。
2> 构造函数声明一般格式为:
构造函数名(类型 1 形参1,类型2 形参2,…)
3> 定义对象的一般格式为 :
类名 对象名(实参1,实参2,…)
2)析构函数
是在一个对象的生命期即将结束的时候,应该回收该对象占有的资源,或是完成一些清理工作。
析构函数既没有返回值,也没有函数参数,因此它不能被重载。
析构函数的语法一般是在类名前加一个“~“。
当对象消亡的时候析构函数会自动被调用。
可以显示调用析构函数。
一般的,不需要进行析构函数显示调用,也会有特殊需求:譬如对象是静态的时候,存在堆区分配,
当程序未结束时候,需要释放堆,这个时候就可以显式调用析构函数来完成。
如果显示调用了析构函数,此时析构函数和普通成员函数是一样的,并不会造成对象被销毁。
#include <iostream>
using namespace std;
class Demo{
public:
Demo(int val) //构造函数:无返回值 与类名 同名 可以有形参 :定义对象时,系统自动调用构造函数
{
myval = val; //
cout << __func__ << __LINE__<<endl; // __func__ :打印当前函数名 __LINE__ 行号
}
~Demo() //析构函数:无返回值 无参数 (默认隐式调用)可显示调用,显示调用后 和普通成员函数一样 不会导致对象消亡
{
cout << __func__ << __LINE__<<endl;
}
public:
int getval()
{
return myval;
}
private:
int myval;
};
Demo obj2(123);
int main()
{
#if 0
Demo obj(666); //构造对象 并给 构造函数 传参 (实例化 obj对象 )
cout << obj.getval() << endl;
#else
//static Demo obj3(555); //静态修饰的局部变量 延长局部对象的生命周期 短于 真正的全局对象
Demo obj(666);
cout << obj.getval() << endl;
Demo *p = new Demo(777); //在堆区 给对象 开辟空间 并 构造
cout << p->getval() << endl;
delete p; //回收 堆区 空间
#endif
return 0;
}
构造顺序: 谁先执行 就先构造 obj2 obj p
析构顺序: 谁先销毁 谁析构 p obj obj2
3.拷贝构造(浅拷贝和深拷贝)
拷贝构造是一种 特殊的构造函数。 copy constructor。
函数名同 类名 无返回值。
参数形式是固定的。
三种情况:
class Demo{
}
1、一般格式
Demo a;
Demo b(a); // Demo b = a;
2、动态的创建对象
Demo a;
Demo *p = new Demo(a);
3、函数传值调用
void test(Demo obj)
{
cout << obj.show() << endl;
}
注意: 一般 拷贝构造是 不会显示调用 ,而是由编译器隐式调用
重点注意:
区分构造和赋值:
构造:
Demo a(1,2);
Demo b(a); //在创建b 对象的时候 通过 会隐式调用拷贝构造 对b对象初始化
赋值:
Demo a(2,4);
Demo b;
b = a; //赋值,不是拷贝构造。
浅拷贝:
只是将成员变量的值 拷贝给 另一个对象
深拷贝:
如果对象的指针成员变量 指向堆区空间, 在拷贝的时候 要开辟新的空间给新对象
this指针是一个特殊的指针,指向类对象自身的首地址。
每个类对象的成员函数都一个this指针,指向调用对象,如果要引用整个对象则*this。
this指针仅能在类内部使用。
#include <iostream>
#include <assert.h>
using namespace std;
class Demo{
public:
Demo (int len)
{
num = len;
p = new char [num];
assert(NULL != p); //
for(int i=0; i<num; i++)
{
p[i] = i;
}
cout << "line:" << __LINE__ <<endl;
}
#if 0
Demo (Demo &obj) //没有重新开辟空间 浅拷贝
{
this->num = obj.num;
this->p = obj.p;
for(int i=0; i<num; i++)
{
this->p[i] = obj.p[i]; // 把obj对象里面的数组 数据 拷贝到 this->p
}
}
#else
Demo (Demo &obj) //重新开辟空间 深拷贝
{
this->num = obj.num;
this->p = new char [num]; //重新开辟空间
assert(NULL != p); //
for(int i=0; i<num; i++)
{
this->p[i] = obj.p[i]; // 把obj对象里面的数组 数据 拷贝到 this->p
}
}
#endif
~Demo()
{
}
private:
char *p;
int num;
};
int main()
{
Demo obj(10);
Demo obj2(obj); // 拷贝构造 拷贝的是数组
return 0;
}