C++基础整理

一、友元

a.友元函数:允许外面的类或函数去访问类的私有变量和保护变量
b.友元类
class A
{

public:
friend class B;

};
类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员
友元类的注意:
1)友元关系不能被继承
2)友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明
3)友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看声明
使用友元函数情况:1)运算符重载的某些场合需要使用友元 2)两个类要共享数据的时候
友元注意:
1)只能出现在类定义内部,友元声明可以在类中的任何地方,一般放在类定义的开始或结尾
2)友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类
3)友元关系不能继承

二、C++输入操作

1)'>>'操作符会丢弃遇到的空白(空格、制表符、换行、回车等)
2)int get() 从输入流中读取一个字符,返回该字符的int值,遇到文件结束符时,返回EOF
3)istream& get(char& ch) 从输入流中读取一个字符,存储在ch中
4)istream& get(char* dst, streamsize size, char delimiter = '\n')
从输入流中读取最多size-1个字符,放入首地址为dst的内存中,会在末尾加'\0'。遇到delimiter时,终止读取,delimiter会留在输入流中
5)istream& getline(char* dst, streamsize size, char delimiter = '\n'),与4)中的get函数类似,只是
getline会读取delimiter然后把它丢弃
6)istream& ignore(streamsize n = 1, int del = EOF)跳过输入流中n个字符,遇到终止符提前
结束(此时跳过包括终止符在内的若干字符),此时终止符任留在流内
7)istream& putback(char ch) 把上一次通过get或getline取得的字符再放回输入流中
8)int peek() 检查流中的下一个字符,它不会删除该字符,字符指针也不会移动
9)streamsize gcount() 返回最后一个非格式化方法(get/getline/ignore/read)读取的字符数
注:>>不是非格式化方法

三、引用

1)声明引用时,必须同时对其进行初始化

2)引用本身不占存储单元,系统也不给引用分配存储单元

3)不能建立数组的引用

4)常引用const int &ra=a; 不能通过引用值来修改变量的值

5)Integer& iRef = Func(); 临时变量(Func()返回做拷贝)给引用初始化,之后对iRef做任何操作都无用,临时变量已经被销毁

即不能从被调函数中返回一个临时变量或局部变量的引用

引用作为返回值,必须遵守以下规则:

1)不能返回局部变量的引用

2)不能返回函数内部new分配的内存的引用

	string& foo()
	{
		string* str = new string("abc");
		return *str;
	}
	void main()
	{
		string str = foo(); //这样申请的内存无法直接释放
		string str = "abc" + foo(); //这样申请的内存无法释放
	}
3)可以返回类成员的引用,但是最好是const

返回指向对象的指针或引用都会被编译器拦住,不能通过类成员函数来修改内部私有变量

4)引用与一些操作符的重载

流操作符<<和>>:这两个操作符希望被连续使用,例如:cout<<"hello"<<"world"<<endl;

则返回一个流对象引用是一个唯一选择,因为引用是针对一个流对象

操作符=:连续等号(x=10)=100,同上是要用引用针对一个对象

5)+-*/四则运算符,不能返回引用,因为这四个操作符没有side effect(映射--输出)

6)引用和多态

引用是除指针外另一个可以产生多态效果的手段,这意味着,一个基类的引用可以指向它的派生类实例

class  A;

class B:public A{...};

B b;

A &Ref = b; //用派生类对象初始化基类对象的引用

Ref只能用来访问派生类对象中基类继承下来的成员,是基类引用指向派生类。

如果A类中定义有虚函数,并且在B类中重写这个虚函数,就可以通过Ref产生多态效果。

使用引用的时机:

流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数等推荐使用引用

四、构造函数后加冒号

1)初始化const成员

2)初始化引用成员

3)当调用基类的构造函数,而它拥有一组参数时

4)当调用成员类的构造函数,而它拥有一组参数时

括号赋值只能出现在变量定义并初始化中比如:int a(10);

有的数据成员需要在构造函数执行之后和执行函数之前进行数据初始化:引用数据成员、常量数据成员(cosnt)、对象数据成员

class student
{
	student()
	{
	protected:	
		const int a;
		int& b; 
	}
}
student :: student(int i, int j) : a(i),b(j) //初始化列表
{
}

五、const修饰

a.const修饰指针变量时:
1)只有一个const,const修饰*左边,则不能修改指针所指向该数据
2)只有一个const,const修饰*右边,则不能修改指针所指向的内存
3)两个const,*左右各一个,则不能改变指针和所指向的数据
b.const修饰成员函数:

class Point
{
public:
	int x; 
	void test(int a) const
	{
		x = a;  //错误,在const成员函数中,不能修改类的成员变量
		modify_x(a);  //错误,const成员函数不能调用非const成员函数,因为非const成员函数会修改成员变量
	}
	
	void modify_x(int x)
	{
	}
	
}
在C++中,临时对象都是const类型的,const类型转化为非const类型是非法的。所以函数引用入参都应该是const类型
int testA(const A& a)
{}
但是对于函数返回值采用“值传递”时,函数返回值不需要加const,因为返回值会先赋值给临时的存储单元
const=非const //正确

非const = const //错误

六、静态类成员

a.静态数据成员
1)静态数据成员实际上是类域中的全局变量。所以,静态数据成员的定义(初始化)不应该被放在头文件中、
xxx.h文件
class base{private: static const int _i;}  //声明在.h类中
xxx.cpp文件
const int base::_i=10;  //定义(初始化)
2)静态数据成员被类的所有对象所共享,包括该类派生类的对象。
3)静态数据成员可以成为成员函数的可选参数,而普通数据成员则不可以

class base{
public:
<span style="white-space:pre">	</span>static int _staticVar;
	int _var;
	void foo1(int i=_staticVar); //正确,_staticVar为静态数据成员
	void foo2(int i=_var);  //错误,_var为普通数据成员
}
4)静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为所属类类型的指针或引用

class base{
public:
	static base _object1;//正确,静态数据成员
	base _object2;//错误
	base *pObject;//正确,指针
	base &mObject;//正确,引用
}
5)静态数据成员的值在const成员函数中可以被合法的改变

b.静态成员函数
1)静态成员函数的地址可用普通函数指针存储,而普通成员函数地址需要用类成员函数指针来存储

class base{
public:
	static int func1();
	int func2();
}
int (*pf1)()=&base::func1;//普通的函数指针
int (base::*pf2)()=&base::func2;//成员函数指针
2)静态成员函数不可以调用类的非静态成员。因为静态成员函数不含this指针
3)静态成员函数不可以同时声明为virtual、const、volatile函数
class base{
	virtual static void func1();//错误
	static void func2() const; //错误
	static void func3() volatile;//错误
}
4)静态成员函数是可以独立访问的,无须创建任何对象实例就可以访问
七、this指针

1)在类的非静态成员函数中返回类对象本身的时候,直接使用return *this;另外当参数与成员变量名相同时,使用this->n = n;
2)this指针存在于类的成员函数中,指向被调用函数所在的类实例的地址。
当调用一个类的成员函数时,编译器将类的指针作为函数的this参数传递进去:
A a;
a.func(10);//此时编译器会看作:A::func(&a, 10);
3)this在成员函数的开始执行前构造,在成员的执行结束后清除

八、关键字inline

1)使用inline,在编译过程中内联函数会直接被源代码替换(减少调用负担),提高执行效率;
如果类中的某个函数会被调用多次或者放在循环中,那么建议将这个函数声明为内联
2)建议把inline函数的定义放到头文件中,以免重复
3)关键字inline必须在函数定义体放在一起才能使函数成为内联,仅将inline放在函数声明前面不起任何作用

void Foo(int x, int y);
inline void Foo(int x, int y)  //inline与函数定义体放在一起
{
} 
4)定义在类声明之中的成员函数将自动地成为内联函数(但是不建议这么写)

九、操作符重载

1)把一个操作符重载类成员函数还是全局名字空间的成员?
类成员函数:

class person
{
	bool operator== (const person &ps) const;
}
inline bool person::operator== (const person &ps)const{
}
全局名字空间的成员:
class person{	
}
bool operator== (person const &p1, person const &p2)
{	
}
如果左操作数为类内对象,则使用类成员函数
2)c++要求赋值=,下标[],调用(),和成员指向->操作符必须被定义为类成员操作符。任何把
这些操作符定义为名字空间成员的定义都会被标记为编译时刻错误
3)如果有一个操作数是类类型如string类,那么对于对称操作符比如等于最好定义为全局名字空间成员

十、临时对象

在使用一个临时对象(可能是无名对象或者返回对象值时)创建构造另一个对象的过程中,c++会优化掉临时对象的产生,直接以相同参数调用相关构造函数或者直接调用拷贝构造函数到目标对象

十一、构造函数

1)普通构造函数:String a("hello")
2)拷贝构造函数:String c = a; //最好写成String c(a);
3)赋值函数:String c; c = a;

class Base
{
<span style="white-space:pre">	</span>Base(const Base& ret):x(ret.x),y(ret.y)  //拷贝构造函数
<span style="white-space:pre">	</span>{		
	}
	String& String::operator= (const String& other)  //赋值函数
	{
		if(this == &other)   //1)检查自赋值
			return *this;
		delete[] m_data;     //2)释放原有的内存资源
		int length = strlen(other.m_data); //3)分配新的内存资源,并复制内容
		m_data = new char[length+1];
		strcpy(m_data, other.m_data);
		return *this;        //4)返回本对象的引用
	}
}
String s2(s1);  
String s3 = s1; //两者都调用了拷贝构造函数,等价
十二、new/delete(析构+operator new/delete)

1)string *ps = new string("hello")
malloc申请完空间之后不会对内存进行必要的初始化,而new可以。所以new expression背后要做事情很多
2)void *operator new(size_t);
  void *operator delete(void *);
  这两个都是用来申请和释放内存的,并且opetator new申请内存之后不对内存进行初始化,直接返回申请内存的指针
3)new的过程:
operator new(8个字节) -- 构造函数初始化 -- 返回新分配并构造号的对象指针
  delete的过程:
调用析构函数 -- opetator delete释放该对象的内存
4)delete[]:
调用析构函数的次数是从数组对象指针前面的4个字节中取出
传入operator delete[]函数的参数不是数组对象的指针pAa,而是pAa的值减4
5)使用new[]用delete来释放对象的前提是:对象的类型是内置类型或者是无自定义的析构函数的类类型
因为不需要析构(即不需要分配前4个字节)
6)new/delete、new[]/delete[] 要配套使用总是没错的!

十三、函数返回引用

1)形参和返回类型都是指向const string对象的引用,调用函数和返回结果时,都没有复制这些string对象

const string &shorterString(const string &s1, const string &str2)
{
<span style="white-space:pre">	</span>return s1.size < s2.size ? s1 : s2;
}
2)返回引用,要求在函数的参数中,包含有以引用方式或指针方式存在的,需要被返回的参数
int& abc(int a, int b, int c, int& result)
{
	result = a + b + c;
	return result;
}
或者:
int& abc(int a, int b, int c, int *result)
{
	*result = a+ b + c;
	return *result;
}
3)返回指向函数调用前就已经存在的对象的引用是正确的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值