您现在的位置是:主页 > news > 学校班级网站建设主页源代码PHP/北京口碑最好的教育机构

学校班级网站建设主页源代码PHP/北京口碑最好的教育机构

admin2025/5/11 6:48:47news

简介学校班级网站建设主页源代码PHP,北京口碑最好的教育机构,酒店网站建设考虑哪些因素,做平面设计兼职的网站有哪些考前看一下 1.通过指针调用成员函数,首先看指针类型是否有这个成员函数 如果有,是否是virtual,如果是,则看对象类型。 如果没有,那么看基类之类的 2.和拷贝构造函数,如果A ac是拷贝构造, A …

学校班级网站建设主页源代码PHP,北京口碑最好的教育机构,酒店网站建设考虑哪些因素,做平面设计兼职的网站有哪些考前看一下 1.通过指针调用成员函数,首先看指针类型是否有这个成员函数 如果有,是否是virtual,如果是,则看对象类型。 如果没有,那么看基类之类的 2.和拷贝构造函数,如果A ac是拷贝构造, A …

考前看一下

1.通过指针调用成员函数,首先看指针类型是否有这个成员函数

如果有,是否是virtual,如果是,则看对象类型。

如果没有,那么看基类之类的

2.=和拷贝构造函数,如果A a=c是拷贝构造, A a; a = c; 是等号

3.const, 只能用const成员函数访问

4.顺序:同级可能在模板,特化,函数中找。顺序是函数>特化>模板

不同级:精确(指针和数组的转化) > 加减const > 类型提升 > 算术转换 > 类类型转换

如果模板,特化,函数匹配到任意一级,直接就输出了,如果没有匹配到,才往下一级

5.在构造函数中,不仅看是否继承了别的类,而且看有类作为成员变量。如果有,调用顺序是基类构造函数->成员变量构造函数->子类构造函数

6.父类和子类同名变量不能覆盖。如果子类调用父类的函数,那么父类函数只能访问父类的成员变量,而不能访问子类的成员变量。

1 类和对象

1.调用没有参数的构造函数不能加括号,比如A a是正确的,A a()是不正确的

2.拷贝构造函数调用的三种情况:

这是等价的:A a = c; A a(c);

函数返回类型A的参数时,函数有类型为A的参数时

如果A构造函数只有一个参数,那么A a = 'c’等价于 A a(‘c’)

通过在构造函数前面加上explicit取消这种方式。

3.如果函数参数表里有const,那么传入一个const类型或者非const类型都可以。如果函数参数表里没有const,那么只能传入非const类型,传入const会错误。

4.常对象只能调用常函数或者静态函数,不能使用普通成员函数

例题1:

#include <iostream>
struct A {A() { std::cout << "A" << std::endl; }A(const A& a) { std::cout << "B" << std::endl; }A& operator=(const A& a) { std::cout << "C" << std::endl; return *this; }
};
int main() {A a[2];A b = a[0];A c;c = a[1];
}

第一个是对象数组,初始化两次

第二个是拷贝,调用拷贝构造函数一次

第三个是初始化,第四个是重载等号

例题2:

#include <iostream>
using namespace std;
class A{
public:static void f(double) {cout << "f(double)" << endl;}void f(int){cout << "f(int)" << endl;}
};
int main(){const A a;a.f(3);
}

常对象不能使用普通成员函数,所以选择了静态函数,输出double

常对象只能使用被const修饰的成员函数或者是静态函数。

2 继承

继承其实是派生类在父类的基础上增加了一些成员函数和变量。因此,拷贝的时候肯定会调用父类的拷贝函数。

1.首先调用基类构造函数,再调用派生类

2.析构函数的顺序正好是相反的。

3.如果遇到虚继承,需要显式调用基类构造函数。但是基类构造函数只会在第一次遇到子类时调用。比如E():A(), B(), C(), D()

其中B,C虚继承了D, 那么调用顺序是A, D, B, C。 从左到右调用构造函数。遇到了虚继承的子类,如果之前没有调用基类,那么首先调用基类。

class A {
public:A() { cout << "A()" << endl; }~A() { cout << "~A()" << endl; }
};class B :public A {
public:B() { cout << "B()" << endl; }~B() { cout << "~B()" << endl; }
};int main() {A a;B b;
}

结果:
A()
A()
B()
~B()
~A()
~A()

3 多态性

1.重载和虚函数区别:父类指针指向子类对象,如果子类重载了父类虚函数,那么可以用父类指针调用子类函数。如果是重载,只能调用父类函数。

因此如果子类想要重载父类的函数,最好将父类函数定义为虚函数

2.纯虚函数是父类中不实现虚函数,而完全由派生类实现。有纯虚函数的类称为抽象类,不能建立对象,不能作为参数类型,不能作为返回类型,可以声明指针或者引用。

3.默认值永远看指针声明时指向的类。不会因为指针指向了子类,调用函数时使用子类的默认值替换基类的默认值。

4.static_cast<> 可以上行下行转化,不会有NULL

dynamic_cast<> 可以进行上行下行转化,但是可能出现NULL

如果基类指针转成派生类指针,会检查基类指针指向对象是不是真的是派生类。如果不是,则变成NULL

const_cast<> 把一个const对象取消const

例题1:

	#include<iostream.h>class Base{publicvirtual void func1(); virtual void func2();  virtual void func3();  void func4();          };class Derivedpublic Base {publicvirtual void func1();void func2(int x); char func3();void func4();};
Base d1,*bp;Derived d2;bp=&d2;bp->func1();     	//调用Derived∷func1()bp->func2();     	//调用Base∷func2()bp->func4();     	//调用Base∷func4()

func1是虚函数重载,因此调用子类

func2子类没有重载虚函数,因此直接调用父类

fun4不是虚函数,因此调用父类

例题2:

#include<iostream.h>class Base{publicBase(int x,int y){   a=x;  b=y; }void show(){cout<<"Base----------\n";cout<<a<<" "<<b<<endl;}privateint a,b;
};
class Derivedpublic Base{publicDerived(int x,int y,int z)Base(x,y){   c=z;   }void show(){cout<< "Derived---------\n";cout<<"c="<<c<<endl;}privateint c;};void main(){Base mb(60,60),*pc;Derived mc(10,20,30);pc=&mb;pc->show();pc=&mc;pc->show();}

pc调用的仍然是基类的show,原因是静态联编,使得指针pc和基类的show绑定在一起。此时如果把基类的show定义为虚函数,则可以正常实现调用。

例题4:

如果基类函数A不是虚函数,子类重载函数A,基类指针p指向子类,调用函数A,只会对子类基类的成员变量进行访问。

如果把A定义为虚函数,则正常对子类所有变量访问。

例题5:

#include <iostream>struct A {virtual void foo(int a = 1) {std::cout << "A" << "\n" << a;}
};
struct B: A {virtual void foo(int a = 2) {std::cout << "B" << "\n" << a;}
};
int main() {A* a = new B;a->foo();
}

B
1.

由于是虚函数,所以指针指向了子类,调用了子类的函数。但是默认值看指针声明时指向的对象,因此使用了基类的默认值。

4 运算符重载

1.正常重载

返回类型 operator 运算符(参数) {函数体};

如果是双元运算,第一个参数是类本身,第二个参数是括号里的。

如果是单元运算,参数填0说明是后置运算,不填是前置运算

注意,如果重载+=这类,必须返回自身的引用。

2.友元函数重载

也可以声明为友元函数,这个跟静态的差不多。

friend 返回类型 operator 运算符(参数1, 参数2){函数体};

类型转换:当出现两个类型运算时,系统首先找有没有重载运算,如果没有,寻找有没有类型转换。

3.类型强制转化

operator 类型(){函数体}; 将该类强制转化为指定类型。

例题1

#include<cstring>
#include<iostream>
using namespace std;class Str {char m_s[10];char* m_p;
public:Str(char* s) { strcpy(m_s, s); m_p = s; }operator char* () { return m_p; }char* operator++() { return ++m_p; }char operator [](int i) { return m_s[i]; }
};int main() {Str s((char*)"Hi");cout << *s << endl;++s;cout << s[0] << endl;cout << *s << endl;
}

operator char*() 就是重载了char*(s),将s转为char*类型的数值返回。

首先,对于*运算符,对象一定是指针类型的,于是看一下s是否可以转为指针类型。发现可以转成char* 类型,于是就转了。返回了m_p,然后把m_p指向的对象直接弄掉。操了

s[0],是m_s第0个,还是’H’(这里要小心)

*s,是*m_p,是’i’

5 输入输出

考个寄吧

6 模板

1.模板全特化:定义函数模板以后,如果要特定的类型不走模板,可以对模板进行特化,如果调用函数的参数和模板特化参数相同,那么调用的是特化的函数

例题1:

#include <iostream>
using namespace std;
template<typename T>
T func(T x, double y){return x+y;}
int main(){cout << func(2.7, 3)<< endl;cout << func(3, 2.7)<< endl;
}

5.7
5
首先,3被转为了double,T被替换为double,返回了double

然后T被替换为int,计算值5.7被转为5

7 STL和类库

考毛线

8 异常处理

这tm还考

异常处理过程:

1.发生异常,首先拷贝一个异常对象

2.寻找catch, 如果未找到转到上一级寻找catch,如果在main中未找到,直接abort

3.如果找到了,对所有try开始到异常点的对象进行析构(异常对象本身也被析构)

4.执行catch内中的语句

5.在catch语句中,可以使用throw; 把原来的对象再次抛出。此时不是拷贝。

类型转换

例题2:

#include <iostream>
using namespace std;
class A {
public:void F(int) { cout << "A: F(int)" << endl; }void F(double) { cout << "A: F(double)" << endl; }void F2(int) { cout << "A: F2(int)" << endl; }
};class B : public A{
public:void F(double) {cout << "B: F(double)" << endl;}
};int main(){B b;b.F(2.0);b.F(2);b.F2(2);
}

B: F(double)
B: F(double)
A: F2(int)

原因是隐式类型转换先于类类型转换

例题3

#include <iostream>
template<class T> void f(T i){std::cout << 1;}
template<> void f(const int i){std::cout << 2;}
int main() {int i = 24;f(i);
}

在第一级匹配到普通函数,输出2

#include <iostream>
template<class T> void f(T& i){std::cout << 1;}
template<> void f(const int& i){std::cout << 2;}
int main() {int i = 24;f(i);
}

第一级匹配到了模板函数,输出1

#include <iostream>
template<class T> void f(T& i){std::cout << 1;}
template<> void f(const int& i){std::cout << 2;}
int main() {const int i = 24;f(i);
}

第一级匹配到了普通函数,输出2

编程

特点:本身不是很难,但是会考c++本身的一些内容,比如模板和异常和常量之类的

1.模板:template<class T>

成员函数定义时候必须加上类参数:

template<class T>
void CC<T> fun(...){//函数初始化
}

2.常函数:声明的时候是int fun(){} const;

定义的时候int fun() const{}

3.常成员变量初始化只能使用参数表

CC(int a): b(a){//构造函数
}

4.类数组,使用的是new class[t]; 不是new class(t),这个是初始化

5.异常就是throw e; 或者throw error(“error”); 调用异常类的构造函数。

异常类的构造函数一般需要一个字符串初始化。

6.注意构造函数不返回任何值,如果需要赋值给一个对象,只能用new

重点

1.几个顺序

构造函数顺序:

基类构造函数->派生类内嵌对象构造函数,按照声明顺序->派生类构造函数体内容。

析构函数相反

函数重载顺序:

1.精确匹配,包括实参类型和形参类型相同,实参从数组或函数转换成对应的指针类型,向实参添加顶层const或从实参删除顶层const

2.通过const转换实现的匹配

3.通过类型提升实现的匹配(short和int, double和float)

4.通过算数类型转换实现的匹配(int 和float之类)

5.通过类类型转换实现的匹配(子类父类)

如果模板,普通函数,特化函数在同一级,顺序是普通函数>特化函数>模板

6.小心对于子类重新定义的成员变量,和基类的变量同名,但是不会被覆盖。也就是说一个类里面存在两个变量。

#include<iostream>
class A {int i;
public :A() :i(0) { }virtual void set(int i) { this->i = i; }virtual int get() { return this->i; }
};class B :public A {int i;
public:B() : i(10) {}virtual void set(int i) { this->i = i; }
};int main() {B b;A* p = &b;std::cout << p->get();
}

由于子类重新定义了i,于是修改和初始化的都是子类的i,基类的i还是0

所以输出0

7.小心虚构函数如果是父类指针,而析构函数不是虚函数,那么不会调用子类的析构函数。

#include<iostream>
using namespace std;
class MyClass {
public:MyClass(int id) { cout << "MyClass::Ctor\n"; }~MyClass() { cout << "MyClass::Dtor\n"; }int id;
};class Base {
public:Base(int id):myClass(id) { cout << "Base::Ctor\n"; }~Base() { cout << "Base::Dtor\n"; }MyClass myClass;virtual void foo() { cout << "Base::foo\n"; }
};class Derived:public Base {
public:Derived(int id) :Base(id) { cout << "Derived::Ctor\n"; foo(); }~Derived() { cout << "Derived::Dtor\n"; }virtual void foo() { cout << "Derived::foo\n"; }
};int main() {Base* p = new Derived(10);delete p;return 0;
}	

输出的是

MyClass::Ctor
Base::Ctor
Derived::Ctor
Derived::foo
Base::Dtor
MyClass::Dtor

8.引用就是相当于别名。引用只允许在初始化的时候赋值,之后的赋值看作调用拷贝,但是内存不变。因此遇到引用,全部换成赋值时的变量名称。

9.遇到问继承的,先画出继承关系。然后看指针的类型,如果指针类型当前函数是虚函数,那么看被指向的对象类型。

10.静态变量就是全局变量。析构函数也是在main里面调用。全局变量中析构函数调用的顺序是按照构造函数的顺序倒过来。

11.在函数中的声明的静态变量,内存在开始时就分配好了。如果多次调用这个函数,那么结果是重新赋值,而不是产生多个静态变量

类中的静态变量,不能在任何函数内赋值,不能在.h里面赋值,.h因为可能被调用多次。

只能在main函数外面赋值。