Practice on programming 学习笔记.

class 1

获得命令行参数

int main(int argc, char *argv[])
{
....

}
argc 代表程序启动时,命令行参数的个数。C/C++语言规定,可执行程序程序本身的文件名也是一个命令行参数,因此argc的最小值为1。

char *argv[] 里存放着指向命令行参数的指针。 copy  file1.txt file2.txt    其中 copy是第一个参数 file1.txt是第二个参数 file2.txt是第三个参数。


class 2

位运算

按位与:通常用来将变量中的某些位清0,且保留其它位不变。也可以用来获取变量中的某一位。

eg:需要将int型变量的低8位全部置为0

n=n&0xffffff00;

如果n是short类型的

n&=0xff00;

按位或:按位或通常用来将某些变量的某些位置置一,其它位保持不变。

按位异或:两个操作数不同置1,相同置0。按位异或运算通常用来将某变量中的某些位取反,其它位保持不变。

eg:将某int变量n的低8位取反

n^=0xff;

异或运算的特点是:若 a^b=c 则 c^b=a以及c^a=b。

这个规律可以用于最简单的加密解密。

a 原文 b 秘钥 c 密文

另外异或运算还能实现不需要临时变量就可以交换两个变量的值。

int a=7, b=5;
a=a^b;
b=b^a;
a=a^b;

左移运算符<<

表达式 a<<b 的值是将a各二进制位全部左移b位后得到的值,左移时,高位丢弃低位补0。

左移n位相当于乘以2的n次方,比乘法操作快很多。

右移运算符>>

右移时,移出的位丢弃。

对于有符号数,如long 、int 、short、char等类型,右移时符号位将一起移动,且大多数C、C++编译器规定,符号位为1高位置1,符号位位0高位补0。

右移你位相当于左操作数除以2的n次方且往小取整。


class 3

内联函数:将整个函数代码插入到调用语句处,而不会产生调用函数的语句。

类对象的大小=类所有成员变量的大小之和。

类中缺省为私有成员。


内联成员函数:

1)inline关键字

2)函数体在类中


class 4

普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。

sizeof 不会计算静态成员变量

普通的成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。

静态成员并不需要通过对象就能访问。

静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在。

静态成员函数本质上是全局函数。

设置静态成员这种机制的目的是将与类紧密相关的全局变量和函数写在类中,看上去像一个整体,便于维护和理解。

必须在定义类的文件中对静态变量进行一次说明或者初始化。

在静态成员函数中不能访问非静态成员变量也不能掉用非静态成员函数。


class 5

成员对象和封闭类

成员对象:一个类的成员变量是另一个类的对象。

包含成员对象的类是封闭类。

当封闭类生成时:第一步执行所有成员对象的构造函数,第二步执行封闭类的构造函数。

成员对象构造函数顺序与成员对象在类中的说明顺序一致,与在成员初始化列表中的顺序无关。

当封闭类对象消亡的时候首先执行封闭类的析构函数,然后执行成员对象的析构函数。


class 6

友元 friend

一个类的友元函数可以访问该类的私有成员。

A是B的友元类,A的成员函数可以访问B的成员。

友元类的关系,不能继承,不能传递。


class 7

从C++程序到C程序的翻译

class CCar{
public:
    int price;
    void SetPrice(int p);
};
void CCar::SetPrice(int P){
    price=p;
}
int main()
{
    CCar car;
    car.SetPrice(10000);
    return 0;
}


struct CCar{
    int price;
};
void SetPrice(struct CCar *this, int p)
{
    this->price=p;
}
int main()
{
    struct CCar car;
    SetPrice(&car,10000);
    return 0;
}


this指针作用

指向成员函数所作用的对象。

静态成员函数中不能使用This指针


class 8 

运算符只能用于基本数据类型

运算符重载:对抽象数据类型也能使用C++原有运算符

运算符重载:对已有运算符赋予多重含义,使同一运算符作用于不同类型的数据时,产生不同的行为。

赋值运算符只能重载为成员函数。

成员函数不能满足使用需求,普通函数又不能访问类的私有成员,可以重载为友元函数。

浅复制:执行逐个字节的复制工作。可能会导致内存垃圾,指针回收的时候会产生严重的内存错误。

深复制:将一个对象指针 变量指向的内容复制到另一个对象中指针成员对象指向的地方。


重载 [ ] 需要注意返回值类型应该是引用类型,否则就不支持 a[i]=elem; 这样的赋值语句。

前置运算符作为一元运算符重载,后置运算符作为二元运算符重载。后置的第二个参数一般为没有意义的0.


class 9

用基类指针数组存放指向各种派生类对象的指针,然后遍历该数组,就能对各派生类对象进行各种操作,是很常用的做法。

example 

Input

3

T 3 4 5

C 9

R 3 4

Out put

CTriangle 5

CRectangle 12

CCycle 254.34

#include <iostream>
#include<stdlib.h>
#include<math.h>
using namespace std;
class CShape
{
public:
	virtual double Area()=0;  //=0意味着虚函数为纯虚函数
	virtual void PrintInfo()=0;
};

class CRectangel:public CShape
{
public:
	int w,h;
	virtual double Area();
	virtual void PrintInfo();
};

class CCycle:public CShape
{
public:
	int r;
	virtual double Area();
	virtual void PrintInfo();
};

class CTriangle:public CShape
{
public:
	int a,b,c;
	virtual double Area();
	virtual void PrintInfo();
};

double CRectangel::Area()
{
	return w*h;
}

void CRectangel::PrintInfo()
{
	cout<<"CRectangle:"<<Area()<<endl;
}

double CCycle::Area()
{
	return 3.14*r*r;
}

void CCycle::PrintInfo()
{
	cout<<"CCyle:"<<Area()<<endl;
}

double CTriangle::Area()
{
	double p=(a+b+c)/2.0;
	return sqrt(p*(p-a)*(p-b)*(p-c));
}

void CTriangle::PrintInfo()
{
	cout<<"CTriangle:"<<Area()<<endl;
}

CShape* pShapes[100];
int myCompare(const void* s1,const void* s2);

int main()
{
	int i,n;
	CRectangel *pr; CCycle *pc; CTriangle *pt;
	cin>>n;
	for(i=0;i<n;i++)
	{
		char c;
		cin>>c;
		switch(c){
		case 'R':
			pr=new CRectangel();
			cin>>pr->w>>pr->h;
			pShapes[i]=pr;
			break;
		case 'C':
			pc=new CCycle();
			cin>>pc->r;
			pShapes[i]=pc;
			break;
		case 'T':
			pt=new CTriangle();
			cin>>pt->a>>pt->b>>pt->c;
			pShapes[i]=pt;
			break;
		}
	}
	qsort(pShapes,n,sizeof(CShape *),myCompare);
	for(i=0;i<n;i++)
		pShapes[i]->PrintInfo();
	return 0;
}

int myCompare(const void* s1,const void* s2)
{
	double a1,a2;
	CShape **p1;
	CShape **p2;
	p1=(CShape**)s1;
	p2=(CShape**)s2;
	a1=(*p1)->Area();
	a2=(*p2)->Area();
	if(a1<a2)
		return -1;
	else if(a2<a1)
		return 1;
	else 
		return 0;
}

在非构造函数,非析构函数的成员函数中调用虚函数,是多态!

多态的关键在于通过基类指针或者引用调用一个虚函数时,编译时不确定调用的是基类的还是派生类的函数,运行时才能确定。----动态联编


把基类的析构函数声明为virtual,通过基类的指针删除派生类对象时,会首先调用派生类的析构函数然后再调用基类的析构函数。

一个类如果定义了虚函数,最好将类的析构函数也定义为虚函数。

纯虚函数:没有函数体的虚函数。

抽象类:包含纯虚函数的类。

抽象类只能作为基类使用,不能创建抽象类的对象。

可以定义抽象类的指针和引用。


class 10 

顺序文件—一个有限字符构成的顺序字符流

使用/创建文件的基本流程   打开文件-》读写文件-》关闭文件


写入文件示例

#include<iostream>
#include<fstream>
#include <cstring>
using namespace std;
class CStudent{
public:
	char szName[20];
	int nScore;
};

int main(){
	CStudent s;
	ofstream OutFile("c:\\tmp\\students.dat",ios::out|ios::binary);
	while(cin>>s.szName>>s.nScore){
		if(stricmp(s.szName,"exit")==0) //名字为exit结束
			break;
		OutFile.write((char*)&s,sizeof(s));
	}
	OutFile.close();
	return 0;
}

读出文件示例

#include<iostream>
#include<fstream>
#include <cstring>
using namespace std;
class CStudent{
public:
	char szName[20];
	int nScore;
};

int main(){
	CStudent s;
	ifstream inFile("students.dat",ios::in|ios::binary);
	if(!inFile)
	{
		cout<<"error"<<endl;
		return 0;
	}
	while(inFile.read((char*)&s,sizeof(s))){
		int nReadedBytes=inFile.gcount();
		cout<<s.szName<<""<<s.nScore<<endl;
	}
	inFile.close();
	return 0;
}


class 11

泛型程序设计

Generic Programming

算法实现时不指定具体要操作的数据的类型。

大量编写模版,使用模版的程序设计。

C++编译器遵循以下优先顺序

1、先找参数完全匹配的普通函数

2、再找参数完全匹配的模版函数

3、在找实参经过自动类型转换后能匹配的普通函数

4、报错













發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章