安徽建设部网站,公众号编辑器365,企业建设H5响应式网站的5大好处,丰和园林建设集团网站文章目录 33、简述一下什么是面向对象#xff1f;34、简述一下面向对象的三大特征#xff1f;35、简述一下 C 的重载和重写#xff0c;以及它们的区别#xff1f;36、说说 C 的重载和重写是如何实现的#xff1f;37、说说构造函数有几种#xff0c;分别什么作用?38、只定… 文章目录 33、简述一下什么是面向对象34、简述一下面向对象的三大特征35、简述一下 C 的重载和重写以及它们的区别36、说说 C 的重载和重写是如何实现的37、说说构造函数有几种分别什么作用?38、只定义析构函数会自动生成哪些构造函数39、说说一个类默认会生成哪些函数40、说说 C 类对象的初始化顺序有多重继承情况下的顺序41、简述下向上转型和向下转型42、简述下深拷贝和浅拷贝如何实现深拷贝43、 简述一下 C 中的多态44、说说为什么要虚析构为什么不能虚构造45、说说模板类是在什么时候实现的46、说说类继承时派生类对不同关键字修饰的基类方法的访问权限48、简述一下移动构造函数什么库用到了这个函数? 33、简述一下什么是面向对象
面向对象是一种编程思想把一切东西看成是一个个对象把这些对象拥有的属性变量和操作这些属性变量的函数打包成一个类来表示。面向过程和面向对象的区别 面向过程根据业务逻辑从上到下写代码 面向对象将数据与函数绑定到一起进行封装加快开发程序减少重复代码的重写过程。
34、简述一下面向对象的三大特征
面向对象的三大特征是封装、继承、多态。 封装将数据和操作数据的方法进行有机结合隐藏对象的属性和实现细节仅对外公开接口来和对象进行交互。封装本质上是一种管理不想给别人看到的我们protected/private把成员封装起来。开放一些共有的成员函数对成员合理的访问。 继承可以使用现有类的所有功能并在无需重新编写原来的类的情况下对这些功能进行扩展。 多态用父类型别的指针指向其子类的实例然后通过父类的指针调用实际子类的成员函数。实现多态有二种方式重写重载。
35、简述一下 C 的重载和重写以及它们的区别
重写 是指派生类中存在重新定义的函数。其函数名参数列表返回值类型所有都必须同基类中被重写的函数一致。只有函数体不同花括号内派生类对象调用时会调用派生类的重写函数不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。
#includebits/stdc.h
using namespace std;
class A {
public:virtual void fun() {cout A;}
};
class B : public A
{
public:virtual void fun() {cout B;}
};
int main(void)
{A* a new B();a-fun();//输出BA类中的fun在B类中重写
}重载 我们在平时写代码中会用到几个函数但是他们的实现功能相同但是有些细节却不同。函数重载是指同一可访问区内被声明的几个具有不同参数列参数的类型个数顺序不同的同名函数根据参数列表确定调用哪个函数重载不关心函数返回类型。
#includebits/stdc.h
using namespace std;
class A
{void fun() {};void fun(int i) {};void fun(int i, int j) {};void fun1(int i,int j){};
};36、说说 C 的重载和重写是如何实现的
重载C利用命名倾轧name mangling技术来改名函数名区分参数不同的同名函数。命名倾轧是在编译阶段完成的。编译时将参数类型加入以区分不同。重写在基类的函数前加上virtual关键字在派生类中重写该函数运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类就调用派生类的函数如果对象类型是基类就调用基类的函数。 虚函数需要注意的地方
用virtual关键字申明的函数叫做虚函数虚函数肯定是类的成员函数。存在虚函数的类都有一个一维的虚函数表叫做虚表类的对象有一个指向虚表开始的虚指针。 虚表是和类对应的虚表指针是和对象对应的。多态性是一个接口多种实现是面向对象的核心分为类的多态性和函数的多态性。重写用虚函数来实现结合动态绑定。纯虚函数是虚函数再加上 0。抽象类是指包括至少一个纯虚函数的类。纯虚函数virtual void fun()0。即抽象类必须在子类实现这个函数即先有名称没有内容在派生类实现内容。
37、说说构造函数有几种分别什么作用?
C中的构造函数可以分为4类默认构造函数、初始化构造函数、拷贝构造函数、移动构造函数。
默认构造函数和初始化构造函数。 在定义类的对象的时候完成对象的初始化工作。 注意有了有参的构造了编译器就不提供默认的构造函数。
class Student
{
public:
//默认构造函数Student() {num1001;age18;}
//初始化构造函数
Student(int n,int a):num(n),age(a){}
private:int num;int age;
};
int main() {
//用默认构造函数初始化对象S1Student s1;
//用初始化构造函数初始化对象S2Student s2(1002,18);return 0;
}拷贝构造函数
#include iostream.h
class Test {int i;int *p;
public:Test(int ai,int value) {i ai;p new int(value);
}~Test() {delete p;}
Test(const Test t) {this-i t.i;this-p new int(*t.p);}
};
//复制构造函数用于复制本类的对象
int main(int argc, char* argv[])
{Test t1(1,2);Test t2(t1);//将对象t1复制给t2。注意复制和赋值的概念不同return 0;
}赋值构造函数默认实现的是值拷贝浅拷贝。 3. 移动构造函数。用于将其他类型的变量隐式转换为本类对象。下面的转换构造函数将int类型的r转换为Student类型的对象对象的age为rnum为1004。
Student(int r)
int num1004int age r38、只定义析构函数会自动生成哪些构造函数
只定义了析构函数编译器将自动为我们生成拷贝构造函数和默认构造函数。 默认构造函数和初始化构造函数。 在定义类的对象的时候完成对象的初始化工作。
class Student
{
public:
//默认构造函数Student() {num1001;age18;}
//初始化构造函数
Student(int n,int a):num(n),age(a){}
private:int num;int age;
};
int main()
{
//用默认构造函数初始化对象S1Student s1;
//用初始化构造函数初始化对象S2Student s2(1002,18);
return 0;
}有了有参的构造了编译器就不提供默认的构造函数。 拷贝构造函数。
#include iostream.h
class Test {int i;int *p;
public:Test(int ai,int value) {i ai;p new int(value);
}~Test() {delete p;}
Test(const Test t) {this-i t.i;this-p new int(*t.p);}
};
//复制构造函数用于复制本类的对象
int main(int argc, char* argv[])
{Test t1(1,2);Test t2(t1);//将对象t1复制给t2。注意复制和赋值的概念不同return 0;
}class HasPtr
{
public:HasPtr(const string s string()) :ps(new string(s)), i(0) {}~HasPtr() { delete ps; }
private:string * ps;int i;
};
HasPtr f(HasPtr hp)
{HasPtr ret hp;///... 其他操作return ret;
}
如果类外面有这样一个当函数执行完了之后将会调用hp和ret的析构函数将hp和ret的成员ps给delete掉但是由于ret和hp指向了同一个对象因此该对象的ps成员被delete了两次这样产生一个未定义的错误所以说如果一个类定义了析构函数那么它要定义自己的拷贝构造函数和默认构造函数。
39、说说一个类默认会生成哪些函数
定义一个空类
无参的构造函数
class Empty {
};拷贝构造函数 拷贝构造函数用于复制本类的对象
Empty(const Empty copy) {
}赋值运算符
Empty operator (const Empty copy) {
}析构函数非虚
~Empty() {
}40、说说 C 类对象的初始化顺序有多重继承情况下的顺序
创建派生类的对象基类的构造函数优先被调用也优先于派生类里的成员类如果类里面有成员类成员类的构造函数优先被调用(也优先于该类本身的构造函数基类构造函数如果有多个基类则构造函数的调用顺序是某类在类派生表中出现的顺序而不是它们在成员初始化表中的顺序成员类对象构造函数如果有多个成员类对象则构造函数的调用顺序是对象在类中被声明的顺序而不是它们出现在成员初始化表中的顺序派生类构造函数作为一般规则派生类构造函数应该不能直接向一个基类数据成员赋值而是把值传递给适当的基类构造函数。综上可以得出初始化顺序 父类构造函数–成员类对象构造函数–自身构造函数 其中成员变量的初始化与声明顺序有关构造函数的调用顺序是类派生列表中的顺序。 析构顺序和构造顺序相反。
41、简述下向上转型和向下转型
子类转换为父类向上转型使用dynamic_cast(expression)这种转换相对来说比较安全不会有数据的丢失父类转换为子类向下转型可以使用强制转换这种转换时不安全的会导致数据的丢失原因是父类的指针或者引用的内存中可能不包含子类的成员的内存。
42、简述下深拷贝和浅拷贝如何实现深拷贝
浅拷贝又称值拷贝将源对象的值拷贝到目标对象中去本质上来说源对象和目标对象共用一份实体只是所引用的变量名不同地址其实还是相同的。举个简单的例子你的小名叫西西大名叫冬冬当别人叫你西西或者冬冬的时候你都会答应这两个名字虽然不相同但是都指的是你。深拷贝拷贝的时候先开辟出和源对象大小一样的空间然后将源对象里的内容拷贝到目标对象中去这样两个指针就指向了不同的内存位置。并且里面的内容是一样的深拷贝情况下不会出现重复释放同一块内存的错误。
43、 简述一下 C 中的多态
由于派生类重写基类方法然后用基类引用指向派生类对象调用方法时候会进行动态绑定这就是多态。
不同的对象收到同一消息可以进行不同的响应,产生完全不同的结果。 多态分为静态多态和动态多态
静态多态编译器在编译期间完成的编译器会根据实参类型来推断该调用哪个函数如果有对应的函数就调用没有则在编译时报错。
includeiostreamusing namespace std;int Add(int a,int b)//1 {return ab;
}char Add(char a,char b)//2 {return ab;
}
int main() {coutAdd(666,888)endl;//1coutAdd(1,2);//2return 0;
}动态多态其实要实现动态多态需要几个条件——即动态绑定条件
虚函数。基类中必须有虚函数在派生类中必须重写虚函数。通过基类类型的指针或引用来调用虚函数。
44、说说为什么要虚析构为什么不能虚构造
虚析构将可能会被继承的父类的析构函数设置为虚函数可以保证当我们new一个子类然后使用基类指针指向该子类对象释放基类指针时可以释放掉子类的空间防止内存泄漏。如果基类的析构函数不是虚函数在特定情况下会导致派生类无法被析构。
用派生类类型指针绑定派生类实例析构的时候不管基类析构函数是不是虚函数都会正常析构用基类类型指针绑定派生类实例析构的时候如果基类析构函数不是虚函数则只会析构基类不会析构派生类对象从而造成内存泄漏。为什么会出现这种现象呢个人认为析构的时候如果没有虚函数的动态绑定功能就只根据指针的类型来进行的而不是根据指针绑定的对象来进行所以只是调用了基类的析构函数如果基类的析构函数是虚函数则析构的时候就要根据指针绑定的对象来调用对应的析构函数了。 C默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针占用额外的内存。
不能虚构造
从存储空间角度虚函数对应一个vtale,这个表的地址是存储在对象的内存空间的。如果将构 造函数设置为虚函数就需要到vtable 中调用可是对象还没有实例化没有内存空间分配如何调用。悖论从实现上看vbtl 在构造函数调用后才建立因而构造函数不可能成为虚函数。
45、说说模板类是在什么时候实现的
模板实例化模板的实例化分为显示实例化和隐式实例化前者是研发人员明确的告诉模板应该使用什么样的类型去生成具体的类或函数后者是在编译的过程中由编译器来决定使用什么类型来实例化一个模板不管是显示实例化或隐式实例化最终生成的类或函数完全是按照模板的定义来实现的。模板具体化当模板使用某种类型类型实例化后生成的类或函数不能满足需要时可以考虑对模板进行具体化。具体化时可以修改原模板的定义当使用该类型时按照具体化后的定义实现具体化相当于对某种类型进行特殊处理。
#include iostream
using namespace std;
// #1 模板定义
templateclass T
struct TemplateStruct {TemplateStruct() {cout sizeof(T) endl;}
};
// #2 模板显示实例化
template struct TemplateStructint;
// #3 模板具体化
template struct TemplateStructdouble {TemplateStruct() {cout --8-- endl;}
};
int main() {TemplateStructint intStruct;TemplateStructdouble doubleStruct;// #4 模板隐式实例化TemplateStructchar llStruct;
}46、说说类继承时派生类对不同关键字修饰的基类方法的访问权限
类中的成员可以分为三种类型分别为public成员、protected成员、public成员。类中可以直接访问自己类的public、protected、private成员但类对象只能访问自己类的public成员。
public继承派生类可以访问基类的public、protected成员不可以访问基类的private成员派生类对象可以访问基类的public成员不可以访问基类的protected、private成员。protected继承派生类可以访问基类的public、protected成员不可以访问基类的private成员派生类对象不可以访问基类的public、protected、private成员。private继承派生类可以访问基类的public、protected成员不可以访问基类的private成员派生类对象不可以访问基类的public、protected、private成员。
48、简述一下移动构造函数什么库用到了这个函数?
移动也使用一个对象的值设置另一个对象的值。移动实现的是对象值真实的转移源对象到目的对象源对象将丢失其内容其内容将被目的对象占有。移动操作的发生的时候是当移动值的对象是未命名的对象的时候。这里未命名的对象就是那些临时变量甚至都不会有名称。典型的未命名对象就是函数的返回值或者类型转换的对象。