暑假資讀[2]

struct、object、指標、參考、運算子重載

講師:張秉中

自我介紹

  • 227
  • OJ上的handle不一(pcc/s10755168/pingchungchang...)
  • 不太會資訊

先講萬用標頭檔

#include <bits/stdc++.h>

https://gist.github.com/Einstrasse/ac0fe7d7450621a39364ed3b05cacd11

指標

pointer

功能

  • 傳遞資料到函式
  • 提高效率
  • 動態資料結構(eg:treap,動態開點線段樹)

語法

  • 宣告: type* (eg:int* a)
  • 取值:*a (eg:*a = 5)
  • 取位址:&a (eg: int* a = &b)

範例

#include <iostream>
using namespace std;

int main(){
	int *a,*b;
	a = new int(5);//new ___ 的回傳值為指標 
	int c = 8;
	b = &c;
	cout<<(*a)+(*b)<<endl;
	b = a;
	*a = 10;
	cout<<(*a)<<' '<<(*b)<<endl;
} 

範例

#include <iostream>
using namespace std;

int main(){
	int *a,*b;
	a = new int(5);//new ___ 的回傳值為指標 
	int c = 8;
	b = &c;
	cout<<(*a)+(*b)<<endl;
	b = a;
	*a = 10;
	cout<<(*a)<<' '<<(*b)<<endl;
} 

13

10 10

參考

reference

功能

  • 相當類似指標
  • 可以想成是一個變數的別名
  • 傳參數到函式
  • 不用考慮一堆&,*

語法

  • 函數型態:type& (eg:int& a)
  • 其他時候當正常變數使用

範例

#include <iostream>
using namespace std;

int main(){
	int b = 10;
	int &a = b;
	a = 13;
	cout<<a<<' '<<b<<endl;
	b = 48763;
	cout<<a<<' '<<b<<endl;
} 

13 13

48763 48763

一些小問題

關於&

  • 指標&:取址
  • 參考&:宣告
  • int&int:位元運算

指標的指標

指標的參考

#include <iostream>
using namespace std;

int main(){
	int a = 5;
	int *b= &a;
	int* &c = b;
	*c = 7414;
	cout<<a<<' '<<*b<<' '<<*c<<endl;
	int** d = &c;
	int *e= new int(10);
	*d = e;
	cout<<a<<' '<<*b<<' '<<*c<<' '<<*(*d)<<' '<<*e<<endl;
}

猜猜看結果

#include <iostream>
using namespace std;

int main(){
	int a = 5;
	int *b= &a;
	int* &c = b;
	*c = 7414;
	cout<<a<<' '<<*b<<' '<<*c<<endl;
	int** d = &c;
	int *e= new int(10);
	*d = e;
	cout<<a<<' '<<*b<<' '<<*c<<' '<<*(*d)<<' '<<*e<<endl;
}

猜猜看結果

#include <iostream>
using namespace std;

int main(){
	int a = 5;
	int *b= &a;
	int* &c = b;
	*c = 7414;
	cout<<a<<' '<<*b<<' '<<*c<<endl;
	int** d = &c;
	int *e= new int(10);
	*d = e;
	cout<<a<<' '<<*b<<' '<<*c<<' '<<*(*d)<<' '<<*e<<endl;
}

函式

function

function

  • f(x) = 3x+10
  • f(x) = 1
  • f(x,y,z) = xyz

...

  • C++ function 只可以回傳一個變數
  • 如果不打算回傳,可以寫void

基本語法

#include <bits/stdc++.h>
using namespace std;

string check(string account,int password){
	if(account == "pcc"&&password == 48763)return "correct";
	else return "error";
}
int main(){
	cout<<check("pcc",48763)<<endl;
	cout<<check("pccc",123)<<endl;
}

指標跟參考跟函式

#include <bits/stdc++.h>
using namespace std;

void swap_value(int *a,int *b){
	int c = *b;
	*b = *a;
	*a = c;
	return;
}
int main(){
	int x = 10,y = 5;
	swap_value(&x,&y);
	cout<<x<<' '<<y<<endl;
}
#include <bits/stdc++.h>
using namespace std;

void swap_value(int &a,int &b){
	int c = b;
	b = a;
	a = c;
	return;
}
int main(){
	int x = 10,y = 5;
	swap_value(x,y);
	cout<<x<<' '<<y<<endl;
}

lambda

  • 可以當成在程式內宣告函式的方式
  • 順便講一下auto
#include <bits/stdc++.h>
using namespace std;
int x = 5;
auto add = [](int a,int b){
	return a+b;
};
int main(){
	int arr[] = {1,2,3,4,5};
	for(int i = 0;i<5;i++){
		cout<<add(arr[i],x)<<',';
	}
	cout<<endl;
	cout<<x<<endl;
	auto minus = [&arr,&x](){
		for(int i = 0;i<5;i++)arr[i] -=x;
		x--;
		return;
	};
	minus();
	for(int i = 0;i<5;i++)cout<<arr[i]<<',';
	cout<<endl;
	cout<<x<<endl;
	minus();
	for(int i= 0;i<5;i++)cout<<arr[i]<<',';
	cout<<endl;
	cout<<x<<endl;
}

lambda

  • capture也可以是lambda欸
#include <bits/stdc++.h>
using namespace std;

int main(){
	int x = 0,y = 0;
	auto g = [](int a,int b){
		return a+b;
	};
	auto f = [&g](){
		return g(g(1,2),g(1,2));
	};
	cout<<f(g);
}

分隔線

本頁以下的內容基本上很少用到(或幾乎用不到)

不會也不會怎樣

(但是右邊那幾頁還是要學喔)

函式指標

Function pointer

  • 就是把function當成變數來儲存
  • 基本上不常用到,除非打模板
#include <bits/stdc++.h>
using namespace std;

string f(int a,int b){
	return string(1,'A'+a-1)+(char)('A'+b-1);
}
int main(){
	string (*func_ptr)(int,int) = f;
	cout<<func_ptr(1,3);
}

函式指標

Function pointer

  • 真的就是把function當成變數來儲存
#include <bits/stdc++.h>
using namespace std;

string f(int a,int b){
	return string(1,'A'+a-1)+(char)('A'+b-1);
}
string g(int c,int d){
	return "hi";
}
int main(){
	string (*func_ptr)(int,int) = f;
	string (*func_ptr2)(int,int) = g;
	vector<string(*)(int,int)> v;
	v.push_back(func_ptr);
	v.push_back(func_ptr2);
	for(int i = 0;i<v.size();i++){
		cout<<v[i](1,3)<<endl;
	}
}

大雜燴

  • capture是空的lambda可以當成function pointer使用
#include <bits/stdc++.h>
using namespace std;

string f(int a,int b){
	return string(1,'A'+a-1)+(char)('A'+b-1);
}
string g(int c,int d){
	return "hi";
}
int main(){
	auto k = [](int a,int b){
		return (string)"AcWaTle";
	};
	string(*func_ptr1)(int,int) = f;
	string(*func_ptr2)(int,int) = g;
	vector<string(*)(int,int)> v = {f,g,k,[](int a,int b){
	return (string)"HIHI";}};
	for(auto &i:v){
		cout<<i(1,3)<<endl;
	}
}

struct

當你想要存一個學生的資料

  • 身高(int)
  • 體重(double)
  • 姓名(string)

How?

  • int height[],float weight[],string name[]
  • tuple<int,float,string>
  • pair<int,pair<float,string>>
  • struct student

How?

  • int height[],float weight[],string name[] 排序不便
  • tuple<int,float,string> 
  • pair<int,pair<float,string>> 當元素很多你就知道了
  • struct student 相對方便,還可以寫函式

語法

Text

struct student{
    int height,birthday;
    float weight;
    char name[30];
};
/*-------------------------------*/
#include <string>
struct student{
    string student_id;
    float weight;
};

語法

Text

#include <iostream>
#include <string>
using namespace std;
struct student{
    int height;
    float weight;
	float bmi;
	string name;
    student(){
        height = 0;
        weight = 0;
        bmi = 0;
        name = "unknown";
    }
    
    student(int h,float w){
    	height = h;
        weight = w;
        bmi = weight/(height/100.0)/(height/(100.0));
    }
    void rename(string s){
    	name = s;
    }
};


int main(){
    student rata(172,45.0);
    rata.rename("ckpc_rata");
    cout<<rata.name<<' '<<rata.bmi;
}

class

  • 基本上競程很少用到
  • 功能大致上跟struct差不多

語法

#include <iostream>
#include <string>
using namespace std;
struct wheel{
	int radius;
	wheel(){}
};
class car{
public:
	wheel wheels;
	string name;
	int x,y;
	void move(int dx,int dy){
		x += dx;
		y += dy;
	}
	car(int px,int py,wheel w,string s){
		wheels = w;
		x = px;
		y = py;
		name = s;
	}
	car(){
		x = y = 0;
		name = "unknown";
	}
private:
	string id;
};


int main(){
	wheel ww;
	ww.radius = 20;
	car bmw(0,0,ww,"my car");
	cout<<bmw.name<<' '<<bmw.wheels.radius<<endl;
	bmw.move(1,2);
	cout<<bmw.x<<' '<<bmw.y<<endl;
//	cout<<bmw.id<<endl; ??????private??? 
}

分隔線

  • 以下的完全用不到(但我覺得蠻好玩的)

繼承

inheritance

  • 當同樣的code不想一直重寫:
#include <bits/stdc++.h>
using namespace std;

#define ll long long

class A{
public:
	int x,y,z;
	A(){
		x = y = z = 0;
	}
	void getval(){
		cout<<x<<y<<z<<endl;
	}
};

class B:public A{
public:
	B(){
		x = y = z = 1;
	}
};

int main(){
	A* a = new B;
	a->getval();
}

header files

自訂標頭檔

編譯指令:g++ -std=c++11 -c ___.o test.h test.cpp others.cpp

g++ -std=c++11 -o test.exe ___.o _____.o _.o(or just *.o)

  • test.h
#include<bits/stdc++.h>
using namespace std;

class CK{
public:
	CK();
	vector<string> students;
	string principal;
	int get_students();
	void change_principal(string s);
};
#include "test.h"
#include <bits/stdc++.h>
using namespace std;


CK::CK(){
	for(int i = 1;i<=33;i++){
		students.push_back(to_string(i));
	}
}
void CK::change_principal(string s){
	principal = s;
}
int CK::get_students(){
	return students.size();
}
int main(){
	int c;
	cin>>c;
	return 0;
}
  • test.cpp

運算子重載

這也很少用到,通常用來除錯或打模版

來看看二維平面

  • a+b?
  • a-b?
  • a*b?
  • a/b?
  • a += b?

來看看二維平面

  • a+b? ->座標相加
  • a-b?  ->座標相減
  • a*b? ->內積
  • a/b? ->外積
  • a += b? 其實就是a = a+b

How?

#include <bits/stdc++.h>
using namespace std;


struct point{
	int x,y;
	point(){
		x = y = 0;
	}
	point(int xx,int yy){
		x = xx,y = yy;
	}
	point operator+(point b){
		return point(x+b.x,y+b.y);
	}
	point operator-(point b){
		return point(x-b.x,y-b.y);
	}
	int operator*(point b){
		return x*b.x+y*b.y;
	}
	point operator*(int k){
		return point(k*x,k*y);
	}
};
point operator+=(point &a,point &b){//也可以寫在struct外
	a.x += b.x;
	a.y += b.y;
	return a;
}
int main(){
	point a(1,2);
	point b(2,-1);
	cout<<a.x<<' '<<a.y<<' '<<(a+b).x<<' '<<a*b<<' '<<(a*3).x<<endl;
}

其他運算子

#include <iostream>
using namespace std;


struct point{
	int x,y;
	point(){
		x = y = 0;
	}
	point(int xx,int yy){
		x = xx,y = yy;
	}
	bool operator<(const point &b)const{//比大小先比x在比y 
		if(x != b.x)return x<b.x;
		else return y<b.y;
	}
};
istream& operator>>(istream& in,point &a){
	in>>a.x>>a.y;
	return in;
}
ostream& operator<<(ostream& out,point a){
	out<<a.x<<' '<<a.y;
	return out;
}

int main(){
	point a(1,2);
	point b(2,-1);
	cin>>a;
	cout<<a<<endl;
}

統整一下一定要會的內容

  • 指標跟參考
  • function
  • struct

這些之後學排序很好用

 

可學可不學的

auto

#include <bits/stdc++.h>

運算子重載

最後做些練習吧

設計一個一維線段的struct line

  • line a(int,int):初始畫線段
  • a.start,a.end:線段的起點跟終點
  • a+b:交集線段
  • a.size():區間長度
  • a.split(int e):由a的起點到e的線段(保證e再線段a內)
  • cout<<a:印出a的起點跟終點位置

一些範例

在main裡加入這堆要可以跑才算成功

line a(1,100);

line b(10,11);

a = a+b;

cout<<a<<endl;

line c(0,a.end);

c.split(a.start)

cout<<c.size()

小練習

寫一個計算2*2矩陣的struct

  • a*b:矩陣乘法
  • det(a):矩陣行列式
  • cin>>a:輸入
  • cout<<a;輸出
  • a+b:元素相加
Made with Slides.com