简介:这些代码和笔记是我在2020年寒假学习C++时所留下的适合进阶C++来时常进行复习
我的学习来源以及摘要是从清华C++进阶课程中摄取吸收
所有的代码都没有加头文件
#include <iostream>
#include <cassert>
#include<vector>
using namespace std;
如果运行的时候出现错误请及时检查以及反馈给我
指针
C++复习第一节课指针数组
int main()
{
int line1[] = { 1,0,0 };
int line2[] = {0,1,0};
int line3[] = {0,0,1};
int* pline[3] = {line1,line2,line3};
cout << "Matrix test" << endl;
for (int i = 0; i < 3; i++)
{
for (int j=0;j<3;j++)
cout << pline[i][j] << " ";
cout << endl;
}
return 0;
}
//Note :函数的参数传递分为值传递、引用传递;
//指针作为参数传递:一、双向传递的作用,二、作为数组的首地址方便数组的传递
练习:读取三个浮点数,将整数部分和小数部分分别输出
void spiltfloat(float x, int* intpart, float * fracpart)
{
*intpart = static_cast<int>(x);//取x的整数部分
* fracpart = x - *intpart;//取x的小数部分
}
int main()
{
cout << "Please enter 3 float point numbers" << endl;
for (int i = 0; i < 3; i++)
{
float x, f;
int n;
cin >> x;
spiltfloat(x, &n, &f);
cout << "Integer part=" << n << " Fractoin part=" << f << endl;
}return 0;
}
指向常量的指针做形参,使得编写程序时遵从最小授权原则
const int N = 6;
void print(const int* p, int n);
int main() {
int array[N];
for (int i = 0; i < N; i++)
cin >> array[i];
print(array, N);
return 0;
}
void print(const int *p,int n) {
cout << "{" << *p;
for (int i = 1; i < n; i++)
cout << "," << *(p + i);
cout << "}" << endl;
}
//指针类型的函数:若函数的返回值是指针,该函数就是指针类型的函数
//不要将非静态局部地址用作函数的返回值(非静态局部变量作用域和寿命都仅限于本函数体内,函数运行结束时,变量被释放)
//错误的例子:在子函数中定义局部变量后将其地址返回给主函数,就是非法地址
//应该返回的指针要确保在主调函数中是有效、合法的地址
int main() {
int array[10];
int* search(int* a, int num);
for (int i = 0; i < 10; i++)
cin >> array[i];
int* zeroptr = search(array, 10);
return 0;
}
int* search(int* a, int num) {
for (int i = 0; i < num; i++)
if (a[i] == 0)
return &a[i];
}
/*
int main() {
int* newintvar();
int* intptr = newintvar();
*intptr = 5;
delete intptr;
return 0;
}
int* newintvar() {
int* p = new int();
return p;
}
*/
指向函数的指针
函数指针的典型用途–实现函数回调
通过函数指针调用的函数(例如将函数的指针作为参数传递给一个函数,使得
在处理相似事件的时候可以灵活的使用不同的方法)
调用者不关心谁是被调用者(需知道存在一个具有特定原型和限制条件的被调函数。)
int compute(int a, int b, int(*func)(int,int)) {
return func(a, b);
}
int max(int a, int b) {
return ((a < b) ? b : a);
}
int min(int a, int b) {
return ((a < b) ? a : b);
}
int sum(int a, int b) {
return a + b;
}
int main() {
int a, b, res;
cout << "请输入整数a:"; cin >> a;
cout << "请输入整数b:"; cin >> b;
res = compute(a, b, &max);
cout << "Max of " << a << " and " << b << " is " << res << endl;
res = compute(a, b, &min);
cout << "Min of " << a << " and " << b << " is " << res << endl;
res = compute(a, b, &sum);
cout << "Sum of " << a << " and " << b << " is " << res << endl;
}
对象指针:
class point {
public:
point(int x=0,int y=0):x(x),y(y){}//这一行是构造函数
//只有类和友元函数可以访问私有成员。
int getx()const { return x; }
int gety()const { return y; }
private:
int x, y;
};
int main() {
point a(4, 5);
point* p1 = &a;
cout << p1->getx() << endl;
cout << a.gety() << endl;
return 0;
}
this指针:指向当前对象自己的指针(相当于python中的self)
class Fred;//前向引用声明
class Barney {
Fred* x;
//光有一个指针没有Fred对象怎么办,可以在构造函数中去用new运算
//动态内存分配,分配一个Barney对象将他的首地址赋给x这个指针,就可以完成
//在Barney类中有Fred类对象,在Fred类中有Barney类对象。
};
class fred {
Barney y;
};
动态分配与释放内存
class point {
public:
point() :x(0), y(0) { cout << "Default Constructor called." << endl; }
point(int x, int y) :x(x), y(y) { cout << "Constructor called" << endl; }
~point() { cout << "Destructor called" << endl; }
int getx()const { return x; }
int gety()const { return y; }
void move(int newx, int newy) {
x = newx;
y = newy;
}
private:
int x, y;
};
int main() {
cout << "Step one :" << endl;
point* ptr1 = new point;
delete ptr1;
cout << "Step two :" << endl;
ptr1 = new point(1, 2);
delete ptr1;
return 0;
}
动态创建对象数组举例
class point {
public:
point() :x(0), y(0) { cout << "Default Constructor called." << endl; }
point(int x, int y) :x(x), y(y) { cout << "Constructor called" << endl; }
~point() { cout << "Destructor called" << endl; }
int getx()const { return x; }
int gety()const { return y; }
void move(int newx, int newy) {
x = newx;
y = newy;
}
private:
int x, y;
};
int main() {
point* ptr = new point[2];
ptr[0].move(5, 10);
ptr[1].move(15, 20);
cout << "Deleting ..." << endl;
delete[]ptr;
return 0;
}
动态创建多维数组
int main() {
int(*cp)[9][8] = new int[7][9][8];
//int (*a)[]定义a是一种指针。a指向一种整数数组。
//对比1的写法,2使用了括号把'*'和a括起来(*a),因为操作符[]的优先级大于*的优先级。
//所以:(*a)是一个数组,数组的每一个元素都是一个整数,而a是指向这个数组的指针。
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 9; j++)
{
for (int k = 0; k < 8; k++)
{
*(*(*(cp + i) + j) + k) = (i * 100 + j * 10 + k);
cout << cp[i][j][k] << " ";
}
cout << endl;
}
cout << endl;
}
delete[]cp;
return 0;
}
动态数组类
class point {
public:
point() :x(0), y(0) { cout << "Default Constructor called." << endl; }
point(int x, int y) :x(x), y(y) { cout << "Constructor called" << endl; }
~point() { cout << "Destructor called" << endl; }
int getx()const { return x; }
int gety()const { return y; }
void move(int newx, int newy) {
x = newx;
y = newy;
}
private:
int x, y;
};
class arrayofpoint {
public:
arrayofpoint(int size) :size(size) {
Point = new point[size];
}
~arrayofpoint() {
cout << "Deleting... "<<endl;
delete[]Point;
}
point& element(int index) {
assert(index >= 0 && index < size);
return Point[index];
}
private:
point* Point;
int size;
};
int main() {
int count;
cout << "Please enter the count of points:";
cin >> count;
arrayofpoint Point(count);
Point.element(0).move(5, 0);
Point.element(1).move(15, 20);
return 0;
}
智能指针
unique_ptr:不允许多个指针共享资源,可以用标准库中的move函数转移指针
shared_ptr:多个指针共享资源
weak_ptr:可复制shared_ptr,但其结构或者释放对资源不产生影响
vector对象
double average(const vector<double>& arr) {
double sum = 0;
for (unsigned i = 0; i < arr.size(); i++)
sum += arr[i];
return sum / arr.size();
}
int main() {
unsigned n;
cout << "n=";
cin >> n;
vector<double>arr(n);
cout << "Please input " << n << " real number:" << endl;
for (unsigned i = 0; i < n; i++)
cin >> arr[i];
cout << "Average =" << average(arr) << endl;
return 0;
}
int main() {
//基于范围的for循环配合auto举例
vector<int>v = { 1,2,3 };
for (auto i = v.begin(); i != v.end(); ++i)
cout << *i << endl;
for (auto e : v)
cout << e << endl;
return 0;
}
浅层复制和深层复制
浅层复制:实现对象间数据元素的一一对应复制
深层复制:当被复制的对象数据成员是指针类型时,不是复制该指针成员本身,而是将指针所指对象进行复制;
版本一:使用深层复制构造函数
返回时构造临时对象,动态分配将临时对象返回到主调函数,然后删除临时对象。
class IntNum {
public:
IntNum(int x = 0) :xptr(new int(x)) { cout << "Calling constructor..." << endl; }
IntNum(const IntNum& n) :xptr(new int(*n.xptr)) { cout << "Calling copy constructor..." << endl; }
~IntNum() { delete xptr; cout << "Destructing..." << endl; }
int getInt() { return *xptr; }
private:
int* xptr;
};
IntNum getNum() {
IntNum a;
return a;
}
int main() {
cout << getNum().getInt() << endl;
return 0;
}
版本二:使用移动构造函数
将要返回的局部对象转移到主调函数,省去了构造和删除临时对象的过程
class IntNum {
public:
IntNum(int x = 0) :xptr(new int(x)) { cout << "Calling constructor..." << endl; }
IntNum(const IntNum& n) :xptr(new int(*n.xptr)) { cout << "Calling copy constructor..." << endl; }
IntNum(IntNum&& n) :xptr(n.xptr) { n.xptr = nullptr; cout << "Calling move constructor ... " << endl; }
//注:&&是右值引用、函数返回的临时变量是右值;
~IntNum() { delete xptr; cout << "Destructing..." << endl; }
int getInt() { return *xptr; }
private:
int* xptr;
};
IntNum getNum() {
IntNum a;
return a;
}
int main() {
cout << getNum().getInt() << endl;
return 0;
}
派生类的构造函数:
如果有多继承以及多个对象的初始化时,
先对基类的继承的顺序依次进行初始化,在对本类的对象定义的顺序进行初始化
class Base1 {
//基类Base1,构造函数有参数
public:
Base1(int i) { cout << "Constructing Base1:" << i << endl; }
};
class Base2 {
//
public:
Base2(int j) { cout << "Constructing Base2:" << j << endl; }
};
class Base3 {
public:
Base3() { cout << "Constructing Base3*" << endl; }
};
class Derived :public Base2, public Base1, public Base3 {
//派生新类Derived,注意基类名的顺序
public:
Derived(int a, int b, int c, int d) :Base1(a), member2(d), member1(c), Base2(b) { }
//注意基类名的个数与顺序,注意成员对象的个数与顺序
private://派生类的私有成员对象
Base1 member1;
Base2 member2;
Base3 member3;
};
int main() {
Derived obj(1, 2, 3, 4);
return 0;
}
运算符重载
重载之后,运算符的优先级和结合性都不会改变
重载为类的非静态成员函数或非成员函数
双目运算符形参个数=原操作数-1(放置的是第二个操作数)
如果是前置的单目运算符就不用接受操作数(即形参)
但如果是后置的单目运算符就会比前置多一个参数,(这个参数)只是为了与前置单目运算符进行区分
双目运算符的重载
class Complex {
public:
Complex(double r=0.0,double i=0.0):real(r),imag(i){}
Complex operator +(const Complex &c2)const;
Complex operator -(const Complex& c2)const;
void display()const;
private:
double real;
double imag;
};
Complex Complex::operator+(const Complex& c2)const {
return Complex(real + c2.real, imag + c2.imag);
}
Complex Complex::operator-(const Complex& c2)const {
return Complex(real-c2.real,imag-c2.imag);
}
void Complex::display()const {
cout << "(" << real << "," << imag << ")" << endl;
}
int main() {
Complex c1(2,5), c2(3,6), c3;
cout << "c1="; c1.display();
cout << "c2="; c2.display();
c3 = c1 + c2;
cout << "c3=c1+c2="; c3.display();
c3 = c1 - c2;
cout << "c3=c1-c2="; c3.display();
return 0;
}
单目运算符的重载
略:有待补充
通过虚函数实现运行时多态
虚函数:编译时,指针无法判断指向的对象,只能将它赋予定义的对象
而定义虚函数以后,就相当于告诉编译器你没法判断指针的类型,只有在运行的时候才能知道
虚函数是属于对象的函数而不是属于类的,因为他是在运行时依靠指针指向的对象
来进行决定调用那个函数体。虚函数进行派生过后就可以实现运行时多态
一般成员函数可以是虚函数
构造函数不能是虚函数
析构函数可以是虚函数
class Base1 {
public:
virtual void display()const;//虚函数,相当于告诉编译器在编译阶段编译到这里你不要做静态绑定,而是在运行时做动态的绑定
};
//当实现了virtual的虚函数就不能在类内定义为内联函数因为内联函数是在编译类时静态绑定,显然与虚函数矛盾
void Base1::display() const{
cout << "Base1::display()" << endl;
}
class Base2:public Base1 {
virtual void display()const;
};
void Base2::display() const {
cout << "Base2::display()" << endl;
}
class Derived:public Base2{
public:
virtual void display()const;//虚函数,相当于告诉编译器在编译阶段编译到这里你不要做静态绑定,而是在运行时做动态的绑定
};
void Derived::display() const {
cout << "Derived::display()" << endl;
}
void fun(Base1 *ptr) {
ptr->display();
}
int main() {
Base1 base1;
Base2 base2;
Derived derived;
fun(&base1);
fun(&base2);
fun(&derived);
return 0;
}
抽象类(含有纯虚函数的类)不能定义实例/对象,可以用来做基类使用,可以用来规定对外接口的统一形式
有待补充
智能指针
今天是2020-3-4下午3:13,晚上要准备同花顺的笔试现在复习到了智能指针,下面是我精炼下来的笔记
智能指针有四个:auto_ptr、unipue_ptr、share_ptr、weak_ptr
其中auto_ptr已经在C++11中被弃用,