欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

【C++ Priemr | 15】面向对象程序设计

发布时间:2023/11/30 49 豆豆
生活随笔 收集整理的这篇文章主要介绍了 【C++ Priemr | 15】面向对象程序设计 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

类型准换与继承

为了支持c++的多态性,才用了动态绑定和静态绑定。

需要理解四个名词:

  • 对象的静态类型:对象在声明时采用的类型,是在编译期确定的。
  • 对象的动态类型:目前所指对象的类型,是在运行期决定的。对象的动态类型可以更改,但是静态类型无法更改。
  • 关于对象的静态类型和动态类型,看一个示例:

    class B {}class C : public B {}class D : public B {}D* pD = new D(); // pD的静态类型是它声明的类型D*,动态类型也是D* B* pB = pD; // pB的静态类型是它声明的类型B*,动态类型是pB所指向的对象pD的类型D* C* pC = new C(); pB = pC; // pB的动态类型是可以更改的,现在它的动态类型是C*

     动态绑定与静态绑定:

    • 静态绑定:又名前期绑定,绑定的是静态类型,所对应的函数或属性依赖于对象的静态类型,发生在编译期;
    • 动态绑定:又名后期绑定,绑定的是动态类型,所对应的函数或属性依赖于对象的动态类型,发生在运行期;

     比如常见的,virtual函数是动态绑定,non-virtual函数是静态绑定,缺省参数值也是静态绑定。

    class B { public:void DoSomething();virtual void vfun(); }class C : public B { public: //首先说明一下,这个子类重新定义了父类的no-virtual函数,这是一个不好的设计,会导//致名称遮掩;这里只是为了说明动态绑定和静态绑定才这样使用。 virtual void vfun(); void DoSomething(); }class D : public B { public:void DoSomething();virtual void vfun(); }D* pD = new D(); B* pB = pD;

    【问题】pD->DoSomething() 和 pB->DoSomething() 调用的是同一个函数吗?
    不是,虽然pD和pB都指向同一个对象。因为函数DoSomething是一个no-virtual函数,它是静态绑定的,也就是编译器会在编译期根据对象的静态类型来选择函数。pD的静态类型是D*,那么编译器在处理pD->DoSomething()的时候会将它指向D::DoSomething()。同理,pB的静态类型是B*,那pB->DoSomething()调用的就是B::DoSomething()。

     

    【问题】pD->vfun() 和pB->vfun() 调用的是同一个函数吗?
    是的,因为vfun是一个虚函数,它动态绑定的,也就是说它绑定的是对象的动态类型,pB和pD虽然静态类型不同,但是他们同时指向一个对象,他们的动态类型是相同的,都是D*,所以,他们的调用的是同一个函数:D::vfun()。

     

    【注意】上面都是针对对象指针的情况,对于引用(reference)的情况同样适用。

    指针和引用的动态类型和静态类型可能会不一致,但是对象的动态类型和静态类型是一致的。

     

    当缺省参数和虚函数一起出现的时候情况有点复杂,极易出错。我们知道,虚函数是动态绑定的,但是为了执行效率,缺省参数是静态绑定的。

    class B { public:virtual void vfun(int i = 10) { cout << "class B: " << i << endl; } };class D : public B { public:virtual void vfun(int i = 20) { cout << "class D: " << i << endl; } };int main() {D* pD = new D();B* pB = pD;pD->vfun();pB->vfun();return 0; }

    输出结果:

    分析:有上面的分析可知pD->vfun()和pB->vfun()调用都是函数D::vfun(),但是他们的缺省参数是多少?缺省参数是静态绑定的,pD->vfun()时,pD的静态类型是D*,所以它的缺省参数应该是20;同理,pB->vfun()的缺省参数应该是10。编写代码验证了一下,正确。

     

    抽象基类

    #include <iostream> using namespace std;class A { public: virtual void out1() = 0;virtual ~A() {};virtual void out2() { cout << "A(out2)" << endl; }void out3() { cout << "A(out3)" << endl; } };class B : public A { public:virtual ~B() {};void out1(){ cout << "B(out1)" << endl; }void out2(){ cout << "B(out2)" << endl; }void out3(){ cout << "B(out3)" << endl; } };int main() {A *ab = new B;ab->out1();ab->out2();ab->out3();cout << "************************" << endl;B *bb = new B;bb->out1();bb->out2();bb->out3();delete ab;delete bb;return 0; }

    输出结果:

     

    c++如何防止一个类被其他类继承?

    如何在防止一个类被其他的类继承呢?

    如果是仅仅为了达到这个目的可以直接把这个类的构造函数设置成私有的,这样就杜绝了其他类的继承。也相当于毁掉了这个类(无法再创造出自己的对象)。

    那么怎么样既要保证这个类的完整性,又防止其他类的继承呢?

    这就要借助友元来实现,因为友元是不可以被继承的。如果一个类的构造函数要借助它的友元类,那么继承了这个类的类就无法构造自己的对象。从而杜绝了被继承。
     

    #include <iostream> using namespace std; class C;class BASE { private:BASE() {}friend class C; //设class C为class BASE的友元 }; class C : public virtual BASE { }; class D :public C { };int main() {C c;//D d; 不可以实例化对象 }

    为什么class C要虚拟继承class BASE 而不是直接继承呢?

    参考资料 

    • c++如何防止一个类被其他类继承

    总结

    以上是生活随笔为你收集整理的【C++ Priemr | 15】面向对象程序设计的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。