类与对象
class A{
private:
int i;
public:
void f();
};
void A::f()
{
i=10;
cout<<i;
}
int main()
{
A a;
a.f();
return 0;
}
class A{
public:
int i;
void f();
};
void A::f()
{
i=10;
cout<<i<<endl;
}
void f(struct A* p)//指针传入类A对象a的地址
{
p->i=20;
cout<<p->i<<endl;
}
int main()
{
A a;
a.f();
cout<<a.i<<endl;
f(&a);
cout<<a.i<<endl;
return 0;
}
动态制造对象(new & delete)
相当于C语言的malloc和free
class A{
int i;
public:
A(){i=0;cout<<"A::A()"<<endl;}
~A(){cout<<"A::~A(),i="<<i<<endl;}
void set(int i){this->i=i;cout<<"i="<<i<<endl;} //调用这个函数对象的i,或者(int ii)i=ii
void f(){cout<<"hello";}
};
int main()
{
A *p = new A[10];
for(int i=0;i<10;i++)
{
p[i].set(i);
}
delete[] p;
return 0;
}
访问权限
-
public:公开的,任何人可以访问
-
private:私有的,只有这个类的成员函数可以访问这些成员变量或成员函数,同一个类的对象之间可以访问
-
protected:只有这个类自己和它的子孙可以访问
-
不去限制访问属性时,class是private,struct是public
-
友元函数是可以直接访问类的私有成员的非成员函数。
-
需要在类的定义中加以声明
-
在调用时不能通过对象调用。也没有this指针。
-
友元函数也可以在类内声明,在类外定义。
```
struct X; //前项声明,告诉编译器X是个东西
struct Y{
void f(X*);
};
struct X{
private:
int i;
public:
void initialize();
friend void g(X*,int);
friend void Y::f(X*);
friend struct Z;
friend void h();
};
void X::initialize(){
i=0;
}
void g(X*x,int i){
x->i=i;
}
void Y::f(X*x){
x->i=44;
}
struct Z{
private:
int j;
};
```
<img src="C:\Users\清昀\AppData\Roaming\Typora\typora-user-images\1692539543617.png" alt="1692539543617" style="zoom:80%;" />
继承
继承与派生:保持已有类的特征构造新类的过程为继承,在已有类的基础上新增特性而产生新类的过程称为派生
class A{
public:
A():i(0) {cout<<"A::A()"<<endl;} //i(0)初始化i=0
~A() {cout<<"A::~A()"<<endl;}
void print(){cout<<"A::f()"<<i<<endl;}
void set(int ii){i=ii;}
private:
int i;
};
class B : public A{ //B是A的子类
};
int main()
{
B b;
b.set(10);
b.print();
return 0;
}
class A{
public:
A(int ii):i(ii) {cout<<"A::A()"<<endl;} //i(0)初始化i=0
~A() {cout<<"A::~A()"<<endl;}
void print(){cout<<"A::f()"<<i<<endl;}
void set(int ii){i=ii;}
private:
int i;
};
class B : public A{ //B是A的子类
public:
B() : A(15){cout<<"B::B()"<<endl;} //调用A的构造函数给它参数
~B() {cout<<"B::~B()"<<endl;}
void f(){
set(20);
print();
}
};
int main()
{
B b;
b.f();
return 0;
}
函数重载
可以将语义、功能相似的几个函数用同一个名字表示,但参数不同(包括类型、顺序不同),即函数重载。
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
内联函数
为了消除函数调用的时空开销,C++ 提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数。 不会出现在最终的可执行代码里,只是会存在于编译器中,在编译器需要的地方插入。
函数小,循环被调用适合inline
class a
{
private:
int i;
public:
a();
void f1();
};
inline a::a()
{
...
}
inline void a::f1()
{
...
}
const与重载
const指针:它所指的对象不能通过它修改
class A{
int i;
public:
A():i(0){}
void f() {cout<<"f()"<<endl;}
void f() const {cout<<"f()const"<<endl;}
};
int main()
{
const A a; //a是const
a.f();
return 0;
}
构成overload重载关系
引用
定义时必须初始化
int main()
{
int x=3;
int& y = x;//y是x的引用(别名)
const int& z=x;//不能通过z对x的改变
cout<<"x="<<x<<endl;
cout<<"y="<<y<<endl;
cout<<"z="<<z<<endl;
y=9;
cout<<"x="<<x<<endl;
cout<<"y="<<y<<endl;
cout<<"z="<<z<<endl;
return 0;
}
-
指针与引用
int* f(int* x){ //传统指针写法,改变&x数据返回指针 (*x)++; cout<<*x<<endl; return x; } int& g(int& x){ //引用写法,返回一个int的引用(reference) x++; return x; } int x; int& h(){ //一个函数的返回结果是reference,故能作为左值被赋值 return x; //让x变量变成reference返回 } int main() { int a = 0; cout<<f(&a)<<endl; cout<<g(a)<<endl; h() = 16; cout<<"x="<<x<<endl; return 0; }
子类父类
uocast:子类的对象被当作父类的对象看待
class A{
public:
int i;
A():i(10){}
};
class B:public A{
private:
int j;
public:
B():j(50) {}
void f() {cout<<"B.j="<<j<<endl;}
};
int main()
{
A a;
B b;
cout<<a.i<<" "<<b.i<<endl;
cout<<sizeof(a)<<" "<<sizeof(b)<<endl;
int *p = (int*)&a;
cout<<p<<" "<<*p<<endl;
*p = 20;
cout<<a.i<<endl;
p=(int*)&b;
cout<<p<<" "<<*p<<endl;
p++;
*p = 60; //改变j的值
cout<<p<<" "<<*p<<endl;
b.f();
return 0;
}
多态
1 必须通过基类的指针或者引用调用虚函数
2 被调用的函数是虚函数,且必须完成对基类虚函数的重写
class A{
public:
A():i(10){}
virtual void f() {cout<<"A::f()"<<i<<endl;}
int i;
};
int main()
{
A a,b;
a.f();
cout<<sizeof(a)<<endl;
int *p = (int*)&a;
int *q = (int*)&b;
cout<<*(p+1)<<endl; //这个才是i的值
cout<<*p<<endl;//地址相同
cout<<*q<<endl;
return 0;
}
通过指针或引用去调用virtual函数才是动态绑定
class A{
public:
A():i(10){}
virtual void f() {cout<<"A::f()"<<i<<endl;}
int i;
};
class B:public A{
public:
int j;
B():j(20) {}
virtual void f() {cout<<"B::f()"<<j<<endl;}
};
int main()
{
A a;
B b;
A *p = &a;
int* r = (int*)&a;
int* t = (int*)&b;
*r = *t; //让a的一块内存指向b的
p->f(); //在a里找j的不存在的内存,故不存在
//p->f(); //调用B的f()
//a=b; //把b的值给了a
//p=&a;
//p->f();
return 0;
}
override覆盖
override表示函数应当重写基类中的虚函数(用于派生类的虚函数中)。
重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数名各不相同(即参数个数或类型不同)。
重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了
-
覆盖是存在类中,子类重写从基类继承过来的函数。但是函数名、返回值、参数列表都必须和基类相同。
-
当子类的对象调用成员函数的时候,如果成员函数有被覆盖则调用子类中覆盖的版本,否则调用从基类继承过来的函数
-
如果子类覆盖的是基类的虚函数,可以用来实现多态。
-
当子类重新定义基类的虚函数之后,基类指针可以根据赋给它不同子类指针动态的调用子类中的虚函数,可以做到动态绑定,这就是多态。
引用plus
void f(const int& i)
{
cout<<i<<endl;
}
int main()
{
int i=3;
f(i*3);
return 0;
}
static
1.静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
2.非静态成员函数可以任意地访问静态成员函数和静态数据成员;
3.静态成员函数不能访问非静态成员函数和非静态数据成员;
4.调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以用类名::函数名调用(因为他本来就是属于类的,用类名调用很正常)
class Rectangle
{
private:
int m_w,m_h;
static int s_sum;
public:
Rectangle(int w,int h)
{
this->m_w = w;
this->m_h = h;
s_sum += (this->m_w * this->m_h);
}
static void GetSum() //这里加上static
{
cout<<"sum = "<<s_sum<<endl;
}
};
int Rectangle::s_sum = 0; //初始化
int main()
{
cout<<"sizeof(Rectangle)="<<sizeof(Rectangle)<<endl;
Rectangle *rect1 = new Rectangle(3,4);
rect1->GetSum();
cout<<"sizeof(rect1)="<<sizeof(*rect1)<<endl;
Rectangle rect2(2,3);
rect2.GetSum(); //可以用对象名.函数名访问
cout<<"sizeof(rect2)="<<sizeof(rect2)<<endl;
Rectangle::GetSum(); //也可以可以用类名::函数名访问
return 0;
}
- 静态全局变量
class A{
public:
A(){i=0;}
void print() {cout<<i<<endl;}
void set(int ii) {i=ii;}
//private:
static int i; //只有声明,需要定义 //作为一个成员的全局变量
};
int A::i = 20; //有static需要这里的定义
int main()
{
A a,b;
a.set(10);
b.print();
cout<<a.i<<endl<<A::i<<endl;
return 0;
}
-
静态函数
class A{ public: A(){i=0;} void print() {cout<<i<<endl;} void set(int i) {this->i=i;} static void say(int ii){cout<<ii<<i<<endl;} static int i; //只有声明,需要定义 //作为一个成员的全局变量 }; int A::i; //有static需要这里的定义 int main() { A a,b; a.set(10); b.print(); cout<<a.i<<endl<<A::i<<endl; A::say(10);//在创建对象前可以访问静态函数 a.say(20); return 0; }
operator运算符重载
class person
{
private:
int age;
public:
person(int nAge)
{
this->age = nAge;
}
bool operator*(const person& ps) //重载*运算符
{
if (this->age == ps.age)
{
return true;
}
return false;
}
void print(){cout<<age<<endl;}
};
int main()
{
person p1(10);
person p2(10);
if (p1 * p2)
{
cout << "p1 is equal with p2." << endl;
}
else
{
cout << "p1 is not equal with p2." << endl;
}
return 0;
}
模板
-
函数模板
template <class 类型参数1, class类型参数2, ...> 返回值类型 模板名(形参表) { 函数体 }
template<class T> void Swap(T & x, T & y) { T tmp = x; x = y; y = tmp; cout<<x<<" "<<y<<endl; } int main() { int n = 1, m = 2; Swap(n, m); //编译器自动生成 void Swap (int &, int &)函数 double f = 1.2, g = 2.3; Swap(f, g); //编译器自动生成 void Swap (double &, double &)函数 return 0; }
-
编译器由模板自动生成函数的过程叫模板的实例化。由模板实例化而得到的函数称为模板函数。
vector
https://blog.csdn.net/fckbb/article/details/130849188
- vector模板是C++标准库中的一个容器类,被设计为动态数组,即它可以根据需要自动分配内存空间来存储元素。 vector模板的本质是一个****类模板**** , vector类使用****连续的内存****来存储元素
定义方式:vector<数据类型>名称
void Swap(T & x, T & y)
{
T tmp = x;
x = y;
y = tmp;
cout<<x<<" "<<y<<endl;
}
int main()
{
int n = 1, m = 2;
Swap(n, m); //编译器自动生成 void Swap (int &, int &)函数
double f = 1.2, g = 2.3;
Swap(f, g); //编译器自动生成 void Swap (double &, double &)函数
return 0;
}
- 编译器由模板自动生成函数的过程叫模板的实例化。由模板实例化而得到的函数称为模板函数。
vector
https://blog.csdn.net/fckbb/article/details/130849188
- vector模板是C++标准库中的一个容器类,被设计为动态数组,即它可以根据需要自动分配内存空间来存储元素。 vector模板的本质是一个****类模板**** , vector类使用****连续的内存****来存储元素
定义方式:vector<数据类型>名称