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;
}

浙公网安备 33010602011771号