当前位置: 首页 > wzjs >正文

免费的舆情网站app嘿客免费网站建设

免费的舆情网站app,嘿客免费网站建设,信阳建网站,网站的安全怎么做C封装、多态、继承C封装封装的定义与目的:把数据和方法统一组织在类中,对外隐藏内部实现,隐藏实现细节- 提供稳定接口- 保证数据有效性- 降低耦合性,提高维护性。封装的实现机制:类作用域、访问控制符、this指针类作用…

C++封装、多态、继承

C++封装

封装的定义与目的:把数据和方法统一组织在类中,对外隐藏内部实现,隐藏实现细节- 提供稳定接口- 保证数据有效性- 降低耦合性,提高维护性。

封装的实现机制:类作用域、访问控制符、this指针

类作用域

作用域:代码中名字(变量、函数等)可被识别和使用的有效范围。

在 C++ 中,常见作用域有:{全局作用域、命名空间作用域、函数作用域、块作用域、类作用域}

类的作用域控制了:类内部成员的名字有效范围、成员访问权限上下文

补充:

如果将类指针强转,则也可以访问到public数据。

访问控制符

虽然类作用域统一包含了所有成员,但访问控制符将它分成了不同“访问级别的区域”,

常见的访问控制符如下:

访问控制符

类内访问

子类访问

类外访问

private

允许

禁止

禁止

protected

允许

允许

禁止

public

允许

允许

允许

访问控制符(private / protected / public)的底层逻辑:

访问控制符是 “编译器层面的语义标签”,它不影响内存,不存在运行时信息,也不会生成额外的机器指令

编译器经历如下处理流程:源代码 -> 词法分析 -> 语法分析 -> 抽象语法树(AST) -> 语义分析 -> 生成中间表示(IR)

访问控制实现阶段:语法分析 + 语义分析阶段

编译器构建 AST(抽象语法树)时,会为每个类成员生成节点,并在节点上打上访问标签。

示例:

CXXRecordDecl MyClass

  |- FieldDecl x (access: private)

  |- FieldDecl y (access: protected)

  |- FieldDecl z (access: public)

  |- CXXMethod setX (access: public)

当编译器在解析类体的时候,它会维护一个 currentAccessSpecifier,一开始是 private(因为 class 默认是 private)。

遇到:private,它会更新 currentAccessSpecifier = AS_private

遇到:public,会更新 currentAccessSpecifier = AS_public

遇到:protected,会更新 currentAccessSpecifier = AS_ protected

然后,编译器接下来遇到的所有成员声明,就会统一打上当前 access 标记

访问控制符不会影响内存结构,无论成员是 public / protected / private,其在类对象中所占用的内存空间是完全一样的。

this指针

this 指针是 C++ 类的成员函数 内部隐式存在的一个指针,指向当前对象自身的地址。

  1. this 是一个 指针,类型为 ClassName* const(常量指针,指向不可变,但指向的对象可变)。
  2. 用于在成员函数内部明确表示 “当前对象”。
  3. 隐藏传入,每个成员函数的调用背后,都隐含传入了 this 指针。

示例:

class Person {

private:

    int age;

public:

    void setAge(int a) { this->age = a; }

};

编译器底层会转成类似这样:

void setAge(Person* this, int a) {

    this->age = a;

}

C++继承

继承:子类(派生类)复用父类(基类)的成员,形成 “is-a” 的关系。

{

注解:

is-a 表示“X 是一种 Y”。

is-a 的本质:子类“属于”父类这个大分类、子类对象可以隐式转换为父类对象指针 / 引用、      子类对象前半部分布局 == 父类布局(子类对象开头就是父类对象,这就是指针兼容性的硬逻辑依据)

}

如果想要运行时多态,继承是必要前提。

继承的三种访问控制

继承方式

父类 public 成员

父类 protected 成员

父类 private 成员

public

保持 public

变成 protected

访问不到

protected

变成 protected

变成 protected

访问不到

private

变成 private

变成 private

访问不到

子类对象的内存模型

class Base {

    int a;

};

class Derived : public Base {

    int b;

};

对象内存布局:

Derived 对象:

[ Base::a ][ Derived::b ],父类成员在子类对象中有“物理存在”!这就是为什么子类对象可以当父类对象用(对象模型兼容性)。

this 指针与继承

Derived d;

d.breathe();

内部等价于:

Animal::breathe(&d);  // this 指向 Derived 对象,但用父类部分去访问

this 指针可以自动向上转为父类类型。这也是为什么多态里 virtual 必须基于指针或引用。

底层实现:对象布局与虚表

普通继承:没有虚表,仅通过偏移访问成员。

Derived d;

Base* p = &d;

p->breathe();  // 编译期已确定,直接偏移访问成员

多态(virtual 函数):

编译器在对象头部插入 vptr(虚表指针):

Derived 对象:

[ vptr ][ Base::a ][ Derived::b ]

vptr 指向 vtable(虚表),vtable 记录所有虚函数地址

C++多态

概念

多态(Polymorphism):同一个接口,不同对象有不同表现。

用统一的父类指针 / 引用,调用不同子类的实现。

动态绑定:运行时决定调用哪一个函数(虚函数机制)。

多态 = vptr 指向 vtable,运行时根据对象真实类型查表找函数

class Animal {

public:

    virtual void speak() { std::cout << "Animal speaks" << std::endl; }

};

class Dog : public Animal {

public:

    void speak() override { std::cout << "Dog barks" << std::endl; }

};

Animal* p = new Dog();

p->speak();   // 输出:Dog barks

如果没有 virtual,输出就永远是 Animal speaks。

静态绑定vs动态绑定

类型

绑定时间

依赖条件

效果

静态绑定

编译期

成员函数(非虚函数)

快,无灵活性

动态绑定

运行期

虚函数 + 指针 / 引用

灵活,代价更高

为什么用指针 / 引用?

只有指针 / 引用才能脱离对象实际类型,让编译器 defer 到运行时决定实际类型。

底层实现原理

本质:虚表(vtable+ 虚表指针(vptr

步骤:

1.编译器生成 vtable

类名

vtable 内容

Animal

&Animal::speak

Dog

&Dog::speak

2. 对象布局插入 vptr

Dog d;

[ vptr -> Dog::vtable ]

[ Animal::成员 ]

[ Dog::成员 ]

3. 调用过程拆解

p->speak();

调用过程等价于

(*(p->vptr)[0])(p);

图解结构:

Dog 对象:

┌──────────┐

vptr ─────────┐

└──────────┘   

               

          ┌────────────┐

          vtable    

          ───────   

          speak ──┐ 

          └────────┬┘ 

                     

                     

               ┌───┴───┴────────────┐

               void Dog::speak()  

               └────────────────────┘

this 指针与多态的结合

void Dog::speak() {

    std::cout << "Dog says, this->type = " << this->type << std::endl;

}

本质:

void speak(Dog* this) {

    ...

}

虚表继承规则

行为

结果

子类未重写虚函数

继承父类 vtable 项

子类重写虚函数

重写覆盖 vtable 对应项

子类新增虚函数

vtable 追加新项

虚表多态 vs 非虚函数

场景

调用行为

非虚函数(静态绑定)

直接根据类型偏移确定地址

虚函数(动态绑定)

运行时查 vtable 决定地址

多态的条件总结

必须条件

理由

虚函数

没有虚表就没有动态绑定

指针 / 引用

否则编译期已确定类型

派生类重写

否则子类不会改变行为

额外知识:vptr 位置

编译器

vptr 插入位置

MSVC

对象头部第一个字节

GCC

对象头部第一个成员位置(隐式)

多态的核心底层模型总结

多态成立条件

底层逻辑

有虚函数

产生虚表,vptr 指向

指针 / 引用

通过 vptr 查虚表调用

重写函数

更新虚表中的函数地址

易错与误解总结

错误理解

正确理解

虚表存在于类

vtable 存在于类,vptr 存在对象

子类一定有新表

没有重写就共享父类表

无指针也有多态

多态只有指针 / 引用才有效

示例:

#include <iostream>

using namespace std;

// -----------  父类 -----------

class Animal {

public:

    string name = "Animal";

    virtual void speak() {  // 虚函数,多态基础

        cout << "Animal speaks!" << endl;

    }

    void breathe() {        // 非虚函数

        cout << "Animal breathes." << endl;

    }

};

// -----------  子类 -----------

class Dog : public Animal {

public:

    string breed = "Bulldog";

    void speak() override {   // 重写虚函数

        cout << "Dog barks!" << endl;

    }

    void fetch() {

        cout << "Dog fetches!" << endl;

    }

};

// -----------  使用父类指针演示多态 -----------

void animalSpeak(Animal* a) {

    a->speak();    // 多态,运行时动态绑定

    a->breathe();  // 非虚函数,静态绑定

}

int main() {

    Dog d;

    cout << "直接调用子类对象:" << endl;

    d.speak();    // Dog::speak,静态绑定

    d.breathe();  // Animal::breathe,静态绑定

    d.fetch();    // Dog::fetch,静态绑定

    cout << "----------" << endl;

    cout << "父类指针指向子类对象,演示多态:" << endl;

    Animal* p = &d;

    p->speak();    // 动态绑定 -> Dog::speak

    p->breathe();  // 静态绑定 -> Animal::breathe

    cout << "----------" << endl;

    cout << "通过统一接口调用:" << endl;

    animalSpeak(&d);

}

输出:

直接调用子类对象:

Dog barks!

Animal breathes.

Dog fetches!

----------

父类指针指向子类对象,演示多态:

Dog barks!

Animal breathes.

----------

通过统一接口调用:

Dog barks!

Animal breathes.


文章转载自:

http://26ZTvs0k.tzjqm.cn
http://BPRcXWLS.tzjqm.cn
http://ZOcxN4aI.tzjqm.cn
http://lPrZjptf.tzjqm.cn
http://sK2x21DH.tzjqm.cn
http://2qDvhLSu.tzjqm.cn
http://nlhXKCbt.tzjqm.cn
http://W3KBIyCh.tzjqm.cn
http://rNgiXWB0.tzjqm.cn
http://mNu5MZ3y.tzjqm.cn
http://SHuMCwb9.tzjqm.cn
http://xYTlMWPS.tzjqm.cn
http://ZUodHH2z.tzjqm.cn
http://DfOULTC6.tzjqm.cn
http://NBZ5bc3q.tzjqm.cn
http://JgTVvwiF.tzjqm.cn
http://mJpmpnBl.tzjqm.cn
http://xnKQuxHa.tzjqm.cn
http://aHzIrCjg.tzjqm.cn
http://DG1lYw6y.tzjqm.cn
http://G1RWuewu.tzjqm.cn
http://s6qtWzjn.tzjqm.cn
http://7VGGiO6i.tzjqm.cn
http://vgnDkBAR.tzjqm.cn
http://HiFsyWEd.tzjqm.cn
http://Q9sXjdm5.tzjqm.cn
http://PomcyCTY.tzjqm.cn
http://B4dYldSo.tzjqm.cn
http://7YAoMKbO.tzjqm.cn
http://1V2JtvZv.tzjqm.cn
http://www.dtcms.com/wzjs/660632.html

相关文章:

  • dwcc如何做网站firefart wordpress
  • 淘宝客论坛响应式php网站下载自己做的网站怎么设置文件下载
  • 好的手机网站推荐创业平台网
  • 网站建设忄金手指稳定北京手机专业网站建设公司
  • 仙居住房和城乡建设规划局网站学了3个月ui好找工作吗
  • 建设共享经济网站的可行性建站知识
  • 个人网站空间价格商城设计方案
  • 做淘宝站外推广网站网站设计步骤有哪些
  • 河北住房城乡建设厅官方网站家政服务网站做推广有效果吗
  • 重庆专业做网站公司公司网站网页设计
  • 网站开发和推广的不同做seo网站的步骤
  • 常熟企业网站建设网站开发维护费用
  • 东莞著名网站建设姑苏区做网站
  • 长沙的网站制作公司系统搭建需要几个步骤
  • 免费建站平台排行榜提升学历图片
  • 信息网站建设情况工作会最好的网站建设系统
  • 引用网站资料怎么注明策划网站做营销推广
  • 外贸平台有哪些小网站网站建设管理属于职业资格吗
  • 网站专题优化外贸网站建设上海
  • 网站开发中网页上传丰台路网站建设
  • 网站如何建数据库安徽住房和城乡建设厅注册网站
  • 电力公司在哪个网站做推广最好做养生的网站多吗
  • 青岛响应式网站开发哪家网站推广做的好
  • 常州免费企业网站建设什么是网络营销产生的基础
  • 网站实现用户登录重庆公司网站建设价格
  • 24小时学会网站建设东莞微网站制作
  • 顺义公司建站多少钱wordpress有商城吗
  • wordpress如何实现支付功天津百度首页优化排名
  • 用dede做的网站一级建造师价格最新行情
  • 网站赢利招商网站建设定做