C++

记录 c++ 学习笔记


\(2022.4.18\)

函数里面的参数不能和 \(private\) 里面的参数同名 , 不然只能用 \(this\) 指定.

类的组合使用要用初始化行列式初始化其他类.


\(2022.4.21\)

关于全局命名空间 与 自我定义的命名空间的优先级.

namespace func{
	int i;
}
int main()
{
	int i = 1;
	func::i=10;
	{
		using namespace func;
		cout<<i;
	}
	return 0;	
} 

结果是 1


\(2022.4.22\)

类里面的静态变量不能用(非)默认构造函数初始化 , 因为它本身就不能在类里面初始化 , 要在类外初始化 , 在类里面叫声明.

#include<iostream>
#include<cstdio>
using namespace std;

class ci{
	public:
		ci() {}; //错误
		pri() { cout<<x; }
	private:
		static int x; //static int x = 3 是错误的.
};

//int ci::x = 0; 类外初始化. 

int main()
{
	ci t;
	t.pri();
	return 0;
} 

\(2022.4.28\)

关于重载的问题

	CTime& operator++()
		{
			second++;
			if(second == 60) second = 0 , minute += 1;
			if(minute == 60) minute = 0 , hour += 1;
			return (*this);
		}
		CTime operator++(int)
		{
			CTime old = (*this);
			++(*this);
			return old;
		}
		friend ostream& operator<<(ostream &out , const CTime &c)
		{
			out<<c.hour<<':'<<c.minute<<':'<<c.second<<'\n';
			return out;
		}

这里做重载 ++(后置) , ++(前置) , << 的对比

\(① :\)
前置++ 返回类型可以加引用 , 也可以不加引用 , 但后置++ (带int) 返回类型一定不能加引用 .
因为在函数内部定义了临时变量 old , 出了函数所占空间就被释放了 , 不可能返回一个不存在的值 .
但不管是 前置++ 或 后置++ 都不能 链式 \(cout<<\) 输出 (这里的 \(<<\) 指已经重载 , 例 $ cout<< a++ << ++a $ .
\(② :\)
重载 \(<<\) 返回类型 一定是 \(ostream\) , 我认为的原因可能要链式输出 ( \(cout<<a<<b<<c\) )
一定要设置友元函数 , \(out\)\(ostream\) 类 , \(out<<\) 类似调用 \(ostream\)\(private\) , 所以必须用友元.
而加减 , 自加自减 是 对类本身 的 操作 , 相当于类的成员函数 , 自然不用友元.
还有一些奇怪的问题就是 必须是 const CTime &c , 或 CTime c , 不能是 CTime &c .
这个问题的出现是因为 cout<<a++ , ++a ; cout<<a ;就有没有 \(const\)\(ok\) .


\(2022.5.12\)

关于类中静态函数和静态变量的使用

#include<iostream>
#include<cstdio>
using namespace std;

class Cat
{
	public:
		Cat(int x) { this->x = x ;  ++HowManyCats; } //构造函数,数量+1 
		~Cat() { --HowManyCats; } // 析构函数,数量减一 
		Cat(Cat& b) { x = b.x ; ++HowManyCats; }//复制构造函数,数量+1 
		int Getx() { return x; }
		static int GetHowMany()//静态函数 
		{
			return HowManyCats;
		}
		static int show(Cat &a)
		{
			//return x; //错误,静态函数对于非静态变量只能具体对象访问 
			return a.x;
		}
	private:
		int x;
		static int HowManyCats;//静态变量的声明. 
};

int Cat::HowManyCats = 0;//静态函数的定义和初始化 

int main()
{
	Cat a(3);
	cout<<a.Getx()<<' '<<Cat::GetHowMany()<<'\n';//静态函数可以直接用类名引用. 
	
	Cat b(a);
	cout<<b.Getx()<<' '<<b.GetHowMany();//静态函数也可以直接用具体对象引用. 
	return 0;
}

关于成员函数设置为友元函数

#include<iostream>
using namespace std;

class X;
class Z;
//X Z类的前置声明
 
class Y
{
	public:
		void g(X *a); //这里对应了X的前置声明 
};
class X
{
	public:
		friend void h(X *a); //声明全局函数h的友元,但这里h并不用放在X的前面写出来 
		friend void Y::g(X *a);//对于类Y的成员函数g的友元,即使前置声明了,也要把Y写在X的前面,因为得到是函数的具体定义,不是声明. 
		friend class Z;//类Z的友元 
		X(int i) {this->i = i;}
		int show() { return i; }
	private:
		int i;	
};
class Z
{
	public:
		void f(X *a) { a->i += 5;}
};
void Y::g(X *a) { a->i += 1; }
void h(X *a) { a->i += 10;	}

int main()
{
	X rec(3);
	Y y;
	Z z;
	cout<<rec.show()<<'\n';
	y.g(&rec);
	cout<<rec.show()<<'\n';
	z.f(&rec);
	cout<<rec.show()<<'\n';
	h(&rec);
	cout<<rec.show()<<'\n';
	return 0;
}

关于多文件编程

Point.h

#include<iostream>
using namespace std;
#define D double

class Point
{
	public:
		friend class AdvCircle;
		void set(D x,D y);
	private:
		double x,y;	
};

//Point类的声明 

AdvCircle.h

#include<iostream>
using namespace std;
#define D double
class Point;

class AdvCircle
{
	public:
		void set(D x,D y,D r);
		void check(Point &a);
	private:
		D x,y,r;		
};

//AdvCircle类的声明 

sol.cpp

#include<iostream>
#include<cmath>
#include"AdvCircle.h"
#include"Point.h"
using namespace std;
#define D double 

void Point::set(D x,D y)//Point的set函数的定义 
{
	this->x = x , this->y = y;
}
void AdvCircle::set(D x,D y,D r) //AdvCircle的set函数的定义 
{
	this->x = x, this->y = y , this->r = r;	
}
void AdvCircle::check(Point &a)//AdvCircle的check函数的定义 
{
	D dis = sqrt( (a.x - x) * (a.x - x) + (a.y - y) * (a.y - y) );
	if(dis > r) { cout<<"Not in the area"; }
	else cout<<"in the area";
}
int main()
{
	Point a;
	AdvCircle b;
	
	a.set(2,3);
	b.set(1,1,2);
	b.check(a);
	return 0;
}

\(2022.5.16\)

关于指针的 取值,自加,自减的问题.

#include<iostream>
#include<cstdio>
using namespace std;

int a[4] = {1,3,5,7};


int main()
{
	int *p = a;
	
	cout<<*p++<<'\n';	//输出的是1 , 说明是先取值再令坐标加加 
	cout<<p<<' '<<&a[1]<<'\n'; 	// p == &a[1];
	
	p = a;
	cout<<*(p++)<<'\n';
	cout<<p<<' '<<&a[1]<<'\n';
	//结果跟上面的相同 , *p++ 和 *(p++) 是等价的.
	
	p = a;
	cout<<*++p<<'\n'; //3 坐标先++再取值.
	
	p = a;
	cout<<++*p<<'\n';//2 先取坐标,再对坐标对应的值++、 
	return 0;
} 

$ 2022.5.17 $

关于 虚函数 和 切片继承的说明

#include<iostream>
#include<cstdio>
using namespace std;

class Base1{
	public:
		void show()	{ cout<<"Base1::show"<<'\n'; }
		virtual void show2() { cout<<"Base1::show2"<<'\n'; }
};
class Base2:public Base1{
	public:
		void show() { cout<<"Base2::show"<<'\n'; }
		void show1() { cout<<"Base2::show1"<<'\n'; }
		void show2() { cout<<"Base2::show2"<<'\n'; }
};

int main()
{
	Base1 a , *p1;
	Base2 b , *p2;
	
	p1 = &b;//把派生类地址赋给基类指针 
	p1->show(); //"Base1::show" , 并不是"Base2::show" 
	//p1->show1() , 并不能使用show1 
	//切片继承
	
	//p2 = &a; 不能把基类地址赋给派生类指针
	
	//引入虚函数后
	p1 = &b;
	p1->show2(); //Base2::show2;
	
	
	//尝试直接赋值
	a = b;
	a.show();//Base1::show 
	//b = a; 错误! 
	return 0;
}

$ 2022.6.23 $

关于纯虚函数和函数重载的一些细节.

#include<iostream>
#include<cstdio>
using namespace std;

class Base1
{
	public:
		virtual void show()=0;
};
class Base2:public Base1
{
	public:
		//int show() { return 1; } //错误 , 因为把 show()看成纯虚函数继承过来的 , 返回值不一致. 
		int show(int a,int b) { return a+b;} // 函数以参数的类型和参数的个数区分重载 , 不以形参名和返回值区分. 
		void show() { cout<<1; } 
};

关于虚基类的例子说明

#include<iostream>
#include<cstdio>
using namespace std;

class Base0
{
	public:
		int var0;
};
class Base1:virtual public Base0
{
	public:
		int var1;
};
class Base2:virtual public Base0
{
	public:
		int var2;	
};
class Base3:public Base1 , public Base2
{
	public:
		int Var3;
};
int main()
{
	Base3 a;
	a.var0 = 1; //如果Base1 , Base2的 "virtual" 删除的话则会报错 , 因为会产生二义性. 
	return 0;
}
posted @ 2022-04-18 21:55  xqy2003  阅读(35)  评论(0)    收藏  举报