高级语言编译过程
1. 源程序(文本文件).cpp --编译--> 目标文件(二进制文件).obj --链接(库文件) --> 可执行文件(二进制文件).exe
C++输入与输出
1. C++没有专门的输入输出语句,所有的输入输出是通过输入输出流来实现的。要使用C++提供的输入输出流,必须在程序开头引入头文件
#include <iostream>
2. 指定输出项占用的宽度
#include <iomanip>
cout << "nga" << setw(10) << "fat" << endl; //向右对齐
内联函数
1. 实质是用空间换时间。原本调用函数时,进入被调函数,返回结果都需要时间。内联函数相当于把调用函数处直接替换成了代码,节省了调用函数、返回的时间
2. 在头文件类体内直接定义函数体时,编译时是作为内联函数实现的。在类体外定义时,需加上关键字inline
重载函数
1. 函数可以具有相同的函数名,C++编译器是根据函数的实参来确定调用哪一个函数的
2. 重载函数必须有不同的参数个数或不同的参数类型
3. 仅返回值不同时,即函数类型不同时,不能定义为重载函数
指针基础
1. 内存以字节为基本单位,每个字节都有编号,称为地址
2. 直接访问通过变量,间接访问通过指针,指针就是存储地址的变量,可以指向任意地址
int a = 10;
int *p = &a; //&a表示变量a的地址
std::cout << p << std::endl; //p表示指针变量p的地址
std::cout << *p << std::endl; //*p表示值
3. 直接访问和间接访问都有其适用的场景,不应该是明明有了直接访问,为什么还要用间接访问的关系。而是有的情况用直接访问更好,有的情况用间接访问更好
4. *在定义变量语句中表示变量的类型是指针,在语句中表示指针变量所指向的值
指针引用
1. 对变量取另外一个名字,这个名字称为该变量的引用
int b = 6;
int &r = b;
2. 引用并没有在内存中开辟空间,它与变量占用同一地址,即同一地址两个名字
3. 指针是通过地址间接访问某个变量,引用是通过别名直接访问某个变量
4. 引用必须初始化,而一旦被初始化后不得再作为其它变量的别名
类与对象
1. 类由数据与函数两部分组成,类是对象的抽象,而对象是类的具体实例
2. private只允许该类中的成员函数使用,protected允许该类及该类的派生类使用,public可以由任意类自由使用
3. 不同对象占据内存中的不同区域,所保存的数据各不相同,但对成员数据进行操作的成员函数的代码均是一样的。当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,然后再调用成员函数
4. getX() const 表明该函数为“只读函数”,不能修改其中的值
静态成员函数
1. 同一个类的不同对象,其数据成员之间是相互独立的。当指定数据成员的存储类型为静态时(用关键字static修饰),该类所有对象的数据成员共享一个存储空间,这个空间在编译时就分配了
2. 静态数据成员只能作一次定义性说明,并且为了保证数据的一致性,通常在定义时赋初值
3. 静态成员函数没有this指针,不能直接使用非静态数据成员
4. 不能把静态成员函数定义为虚函数
构造函数和析构函数
1. 构造函数是在创建对象时,使用给定的值将对象初始化。析构函数的功能正好相反,在释放对象前,做一些善后工作,如delete
拷贝构造函数(复制构造函数)
1. 用来完成一些基于同一类的其他对象的构建及初始化
2. 其形参必须是引用
3. 通常用于:通过另一个同类型的对象来初始化新创建的对象、复制对象作为参数,复制对象返回
4. 如果没有定义构造函数,编译器会自行定义一个。但如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数
#include <iostream>
class Test
{
public:
Test();
~Test();
Test(int x);
Test(const Test &test); //拷贝构造函数,不能省略
void Display(Test test); //复制对象作为参数时调用拷贝构造函数
private:
int *px_;
};
Test::~Test()
{
delete px_;
}
Test::Test(int x)
{
std::cout << "构造函数" << std::endl;
px_ = new int;
*px_ = x;
}
Test::Test(const Test &test)
{
std::cout << "拷贝构造函数" << std::endl;
px_ = new int;
*px_ = *test.px_;
}
void Test::Display(Test test)
{
std::cout << *test.px_ << std::endl;
}
int main()
{
Test test(6);
test.Display(test);
return 0;
}
友元
1. 友元是一种定义在类外部的普通函数或类,但它需要在类内部进行说明
2. 为了与该类的成员函数加以区别,在说明时前面加关键字friend
3. 友元不是成员函数,但是可以访问类中的私有成员,通常用来取对象中的数据成员值而不修改值
4. 目的:对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查都需要开销,使用友元可以提高程序运行效率
5. 缺点:破坏了类的封装性和隐蔽性
6. 友元函数近似于普通函数,它不带this指针,因此必须将对象名或对象的引用作为友元的参数,这样才能访问到对象的成员
7. 友元函数不受类中访问权限关键字的限制
8. 友元关系不能被继承,不具有交换性,不具有传递性
动态内存
1. 利用new运算符可以在程序中动态开辟内存空间
2. new相当于一个函数,在内存开辟完空间后,返回这个空间的首地址,这时,这个地址必须用一个指针保存下来,才不会丢失
3. 用new开辟的内存单元没有名字,指向其首地址的指针是引用其的唯一途径,若指针变量重新赋值,这块内存单元就在内存中“丢失”了,别的程序也不能占用,直到重启,称为内存泄露
4. 用new运算符分配的空间,不能再分配空间时进行初始化
5. 同样用new开辟的内存单元如果不主动收回,也会造成内存泄露,因此用delete运算符将动态分配到的内存空间归还给系统
运算符重载
1. 可以重载大部分C++内置的运算符,以实现自定义类型的运算符
2. 重载运算符是带有特殊名称的函数,函数名由关键字operator和其后要重载的运算符符号构成
#include <iostream>
class Test
{
public:
Test();
~Test();
void setl(double length)
{
l = length;
}
void setw(double width)
{
w = width;
}
void seth(double height)
{
h = height;
}
double getv()
{
return l * w * h;
}
Test operator+(const Test &test)
{
Test test_tmp;
test_tmp.l = this->l + test.l;
test_tmp.w = this->w + test.w;
test_tmp.h = this->h + test.h;
return test_tmp;
}
Test operator++()
{
Test test_tmp;
test_tmp.l = ++l;
return test_tmp;
}
//括号中有int表示后缀
Test operator++(int)
{
Test test_tmp;
test_tmp.l = l++;
return test_tmp;
}
private:
double l;
double w;
double h;
};
Test::Test():l(0), w(0), h(0)
{}
Test::~Test()
{}
int main()
{
Test test1, test2, test3;
test1.setl(1);
test1.setw(2);
test1.seth(3);
test2.setl(3);
test2.setw(2);
test2.seth(1);
test3 = test1 + test2;
std::cout << test3.getv() << std::endl;
++test3;
std::cout << test3.getv() << std::endl;
}