C++多态特性之派生与虚函数与模板详细介绍

目录
  • 继承与派生
  • 虚函数
    • 父类代码如下
  • 模板
    • 函数模板
    • 类模板
    • 字符串

继承与派生

C ++ 是面向对象编程,那么只要面向对象,都会有多态、继承的特性。C++是如何实现继承的呢?

继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类 A,那么 B 就拥有 A 的成员变量和成员函数。

在C++中,派生(Derive) 和继承是一个概念,只是站的角度不同。继承是儿子接收父亲的产业,派生是父亲把产业传承给儿子。

被继承的类称为父类或基类,继承的类称为子类或派生类。“子类”和“父类”通常放在一起称呼,“基类”和“派生类”通常放在一起称呼。

在C++中继承称为派生类,基类孵化除了派生类,使用:来表示子类继承父类,C++中支持多继承,使用逗号分隔

class Parent {
public:
    int name;
protected:
    int code;
private:
    int num;
};
class Parent1 {
};
// C++中,:表示继承,可以多继承逗号分隔
// public/protected/private继承,对于基类起到一些保护机制 默认是private继承
class Child : public Parent, Parent1 {
    void test() {
        // 派生类可以访问到public属性和protected属性
        this->name;
        this->code;
    }
};

C++中派生类中添加了public 派生、protected派生、private派生,默认是private派生

class 派生类名:[继承方式] 基类名{ 派生类新增加的成员 };

class Parent {
public:
    int name;
protected:
    int code;
private:
    int num;
};
class Parent1 {
};
// private私有继承
class Child1 : private Parent {
    void test() {
        this->name;
        this->code;
    }
};
// protected继承
class Child2 : protected Parent {
    void test() {
        this->name;
        this->code;
    }
};

public 派生、protected派生、private派生对于,创建的对象调用父类的属性和方法起到了限制和保护的作用

    Child child;
    child.name; // public继承。调用者可以访问到父类公有属性,私有属性访问不到的
    Child1 child1;
//    child1.name; // private继承.调用者访问不到父类公有属性和私有属性
    Child2 child2;
//    child2.name; // protected继承,调用者访问不到父类公有属性和私有属性

虚函数

重点!!! C++的继承和java中的继承存在的不同点: 基类成员函数和派生类成员函数不构成重载

基类成员和派生类成员的名字一样时会造成遮蔽,这句话对于成员变量很好理解,对于成员函数要引起注意,不管函数的参数如何,只要名字一样就会造成遮蔽。换句话说,基类成员函数和派生类成员函数不会构成重载,如果派生类有同名函数,那么就会遮蔽基类中的所有同名函数,不管它们的参数是否一样。​

父类代码如下

#include <cstring>
#include <iostream>
using namespace std;
class Person {
protected:
    char *str;
public:
    Person(char *str) {
        if (str != NULL) {
            this->str = new char[strlen(str) + 1];
            strcpy(this->str, str);
        } else {
            this->str = NULL;
        }
        cout << "parent" << endl;
    }
    Person(const Person &p) {
        cout << "copy parent" << endl;
    }
    void printC() {
        cout << "parent printC" << endl;
    }
    ~Person() {
//        if (str != NULL) {
//            delete[] str; // 如果调用了这个方法只会调用一次析构函数
//        }
//        cout << "parent destroy" << endl;
    }
};

子类继承父类,并且调用父类的构造函数, 通过:来调用父类的构造函数

// 子类
class CTest : public Person {
public:
    // 调用父类的构造方法
    CTest(char *str) : Person(str) {
        cout << "child" << endl;
    }
    void printC() {
        cout << "child printC" << endl;
    }
    ~CTest() {
        cout << "child destroy " << endl;
    }
};

在C++中和Java的不同在于如下代码:只要是父类的指针都是调用的父类的方法,哪怕子类对象直接赋值给父类,也会调用父类的方法,而不会调用子类的方法。

int main() {
    Person person = CTest("jake");
    person.printC(); // parent printC
    cout << "-----------" << endl;
    Person *p = NULL;
    CTest c1("123");
    p = &c1;
    c1.printC(); // child printC
    p->printC(); // parent printC 为什么会调用的是parent的方法呢?
    return 0;
}

parent
child
copy parent
child destroy 
parent printC
-----------
parent
child
child printC
parent printC
child destroy

哪怕通过指针传递和引用传递,只要使用的父类都会调用父类的方法

// 通过指针传递只会调用父类的方法,不会调用子类的方法
void howToPaint(Person *p) {
    p->printC();
}
// 通过引用类型,只会调用父类的方法,不会调用子类的方法
void howToPaint1(Person &p) {
    p.printC();
}
cout << "---------" << endl;
howToPaint(p); // parent printC
howToPaint(&c1); // parent printC
cout << "-------" << endl;
Person p1("123");
// 都是父类的方法
howToPaint1(p1); // parent printC
howToPaint1(c1); // parent printC
cout << "--------" << endl;
CTest c2("123");
Person p2 = c2; // 会不会调用父类的拷贝函数呢? copy parent 会进行调用

---------
parent printC
parent printC
-------
parent
parent printC
parent printC
--------
parent
child
copy parent
child destroy 
child destroy

这是为什么呢?

C++ 中会按照函数表的顺序进行调用,很显然父类的函数是在子类函数的前面的

那么如何调用到子类的方法呢?C ++提供了虚函数的方式,虚函数也是实现多态的关键。​

虚函数与纯虚函数,纯虚函数在java 中 abstract == 纯虚函数

实际开发中,一旦我们自己定义了析构函数,就是希望在对象销毁时用它来进行清理工作,比如释放内存、关闭文件等,如果这个类又是一个基类,那么我们就必须将该析构函数声明为虚函数,否则就有内存泄露的风险。也就是说,大部分情况下都应该将基类的析构函数声明为虚函数。

包含纯虚函数的类称为抽象类(Abstract Class)。之所以说它抽象,是因为它无法实例化,也就是无法创建对象。原因很明显,纯虚函数没有函数体,不是完整的函数,无法调用,也无法为其分配内存空间。

抽象类通常是作为基类,让派生类去实现纯虚函数。派生类必须实现纯虚函数才能被实例化。

  • 一个纯虚函数就可以使类成为抽象基类,但是抽象基类中除了包含纯虚函数外,还可以包含其它的成员函数(虚函数或普通函数)和成员变量。
  • 只有类中的虚函数才能被声明为纯虚函数,普通成员函数和顶层函数均不能声明为纯虚函数。
  • 基类的析构函数必须声明为虚函数。
#include <iostream>
using namespace std;
class Person {
public:
    // 增加了一个虚函数表的指针
    // 虚函数 子类可以覆写的函数
    virtual void look() {
        cout << "virtual look" << endl;
    }
    // 纯虚函数 必须要让子类实现的
    virtual void speak() {};
    // 基类的析构函数必须声明为虚函数
    virtual ~Person() {
        cout << "~Person" << endl;
    }
};
class Child : public Person {
public:
    // 子类实现纯虚函数
    void speak() override {
        cout << "child speak" << endl;
    }
    // 访问父类的方法
    void look() override {
        cout << "child look" << endl;
        Person::look();
    }
    ~Child() {
        cout << "~Child" << endl;
    }
};
int main() {
    Person *person = new Child(); // 必须通过指针的方式,不同通过栈的方式去派生抽象
    person->speak(); // child speak
    person->look(); // child look
    Person p;
    cout << sizeof(p) << endl; // 8 这就表明了虚函数是有一个虚函数表,增加一个指针*vtable,指向了虚函数表
    // 下面代码来证明
    typedef void (*func)(void);
    func fun = NULL;
    cout << (int *) &p << endl; // 指向函数的首地址 0x16ee1efa8
    cout << (int *) *(int *) &p << endl; // 函数的地址 0xfe40a0
    fun = (func) *((int *) *(int *) &p);
    fun(); // virtual look
    return 0;
}
/**
 * child speak
 * child look
 * virtual look
 * ~Child
 * ~Person
 */

child speak
child look
virtual look
8
0x16ee1efa8
0xfe40a0

模板

模板和java的泛型类似。 模板类不支持声明(.h)和实现(.cpp)分开写,「不能将模板的声明和定义分散到多个文件中」的根本原因是:模板的实例化是由编译器完成的,而不是由链接器完成的,这可能会导致在链接期间找不到对应的实例。

函数模板

#include <iostream>
#include <string>
#include <cstring>
using namespace std;
/**
 * 函数模板和java中的泛型类似
 */
// 方法泛型 这里只能声明在方法上
template<typename T, typename R=int>
// R的默认类型是int
// typename == class 两个等价的
void swap2(T t, R r) {
}
template<typename T>
void swapT(T &a, T &b) {
    cout << "swap: T a T b" << endl;
    T temp = a;
    a = b;
    b = temp;
}
// 普通函数优先级比泛型函数高,只有类型重合的状态下
void swapT(int &a, int &b) {
    cout << "swap : int a int b" << endl;
    int temp = a;
    a = b;
    b = temp;
}
int main() {
    // 函数模板
    int a = 10;
    int b = 20;
    char c = 'a';
    swapT<int>(a, b); // 显示调度
    swapT(a, b); // 自动推导
//    swap(a,c); // 报错 无法推导出具体的类型
//    swap2(); // 报错 无法推导出具体的类型
    char *a1 = "abc";
    char *a2 = "123";
    cout << a1 << a2 << endl;
    swapT(a1, a2);
    cout << a1 << a2 << endl;
    return 0;
}

swap: T a T b
swap : int a int b
abc123
swap: T a T b
123abc

类模板

#include <iostream>
#include <cstring>
using namespace std;
// 模板修饰在类上
template<typename T, typename R>
class Person {
public:
    T a;
    R b;
    Person(T t) {
    }
    T &getA() {
        T t1;
//        return t1; // 这里不可以返回,因为方法执行完毕后会销毁掉
        return a; // 返回值是引用
    }
};
/**
 * 和java不同的部分,比java更加灵活
 */
class Pp {
public:
    void show() {
        cout << "Pp show" << endl;
    }
};
template<typename T>
class ObjTemp {
private:
    T obj;
public:
    void showPp() {
        // 自动检查 但是会出现不可预期的错误
        obj.show(); // 假设模板是Pp,可以调用Pp的变量和方法,在java中需要<T extend Pp> T才能调用方法
    }
};
template<typename T, typename R>
class CTest {
public:
    T m_name;
    R m_age;
    CTest(T name, R age) {
        this->m_name = name;
        this->m_age = age;
    }
    void show() {
        cout << "show T:" << m_name << " R:" << m_age << endl;
    }
};
template<typename T, typename R>
void doWork(CTest<T, R> &cTest) {
    cTest.show();
}
template<typename T>
void doWork2(T &t) {
    t.show(); // 在java中必须是<T extend xxxx>
}
// 继承模板问题和java是一样的
template<typename T>
class Base {
public:
    T t;
};
// 确定的类型或者模板
template<typename T, typename R>
class Son : Base<R> {
public:
    T t1;
};
int main() {
    CTest<string, int> test("后端码匠", 28); // show T:后端码匠 R:28
    doWork(test);
    doWork2<CTest<string, int>>(test); // 显示调用
    doWork2(test); // 自动推导
    ObjTemp<Pp> temp;
    temp.showPp(); // Pp show 可以调用传递过来的模板的方法
    // 自动类型推导,在类模板上不可以使用,无法推导出具体的类型
    Person<int, string> p(100);
    cout << p.getA() << endl;
    return 0;
}

show T:后端码匠 R:28
show T:后端码匠 R:28
show T:后端码匠 R:28
Pp show
0

实现一个模板类ArrayList类似Java的列表实现:

注意在之前学习的.h和.cpp分开的方式,不支持模板,一般模板的部分都会合并到.h文件中。

#include <iostream>
#include <cstring>
using namespace std;
#ifndef CPPDEMO_ARRAYLIST_H
#define CPPDEMO_ARRAYLIST_H
template<typename T>
class ArrayList {
public:
    int d = 11;
    ArrayList() {
        this->size = 16;
        this->realSize = 0;
        this->arr = new T[this->size];
    }
    // explicit 不能通过隐式调用
    explicit ArrayList(int capacity) {
        this->size = capacity;
        this->realSize = 0;
        // 在堆区申请数组
        this->arr = new T[this->size]; // 在堆中开辟的一块空间 存储的是一个int[size] 数组,arr指向数组的首地址
    }
    // 拷贝函数
    ArrayList(const ArrayList &arrayList) {
        this->size = arrayList.size;
        this->realSize = arrayList.realSize;
        this->arr = new T[arrayList.size];
        // 将数组的值赋值到arr中
        for (int i = 0; i < this->size; ++i) {
            this->arr[i] = arrayList.arr[i]; // arrayList.arr[i]他也是指针  this->arr[i] 是指针
        }
    }
    // 析构函数
    ~ArrayList() {
        if (this->arr != nullptr) {
            delete[] this->arr;
            this->arr = nullptr;
        }
    }
    void add(T val) {
        add(val, this->realSize);
    }
    void add(T val, int index) {
        if (index < 0 || index > size) {
            return;
        }
        // 判断容量是否够大 不够进行扩容
        if (this->realSize >= size * 0.75) {
            resize();
        }
        this->arr[index] = val; // 等价于   *((this->arr)+index) = val
        this->realSize++; // 数据量大小+1
    }
    T get(int index) {
        if (index < 0 || index >= realSize) {
            return -1;
        }
        return this->arr[index];
    }
    T remove(int index) {
        if (index < 0 || index >= realSize) {
            return -1;
        }
        // 如何移除呢?循环往前移动
        int result = this->arr[index];
        for (int i = index; i < size - 1; ++i) {
            this->arr[i] = this->arr[i + 1];
        }
        this->realSize--;
        // 判断缩减容量
        return result;
    }
    // const 定义为常函数
    int getLength() const {
        // realSize = realSize - 1; 这样会报错 不能修改函数内部的所有变量
        c = 11; // mutable 修饰的变量可以在常函数中修改
        return realSize;
    }
    bool isEmpty() const {
        return realSize == 0;
    }
    void resize() {
        int netLength = size * 2;
        T *p = new T[netLength];
        // 拷贝数据
        for (int i = 0; i < size; ++i) {
            *(p + i) = this->arr[i];
        }
        // 释放之前的数组
        delete[] this->arr;
        // 重新赋值
        this->arr = p;
        this->size = netLength;
    }
    void toString() {
        cout << "[ ";
        for (int i = 0; i < realSize; ++i) {
            cout << arr[i] << ", ";
        }
        cout << " ] " << endl;
    }
private:
    int size{}; // 容器的大小
    int realSize{}; // 真实的数组长度
    T *arr; // 这里不能使用数组,因为数组名是arr指针常量,不能对arr重新赋值, 指针是指针变量,而数组名只是一个指针常量
    mutable int c = 10; // 可以在常函数中修改的变量 需要使用mutable进行修饰
};
int main() {
    ArrayList<int> arrayList;
    arrayList.add(1);
    arrayList.add(2);
    arrayList.add(3);
    arrayList.add(4);
    arrayList.add(5);
    arrayList.add(6);
    for (int i = 0; i < arrayList.getLength(); ++i) {
        cout << arrayList.get(i) << endl;
    }
    return 0;
}
#endif // CPPDEMO_ARRAYLIST_H

1
2
3
4
5
6

字符串

int main() {
    // 字符串 string 是C++独有的string是一个对象,内部封装了和C一样的字符串的表现形式
    string s1();
    string s2("123");
    string s3 = "wew"; // string字符串是声明在堆区的
    string s4(4, 'k'); // 4个K组成 kkkk
    string s5("123456", 1, 4); // 从1开始,输出四个字符串:2345
    cout << s4 << " " << s5 << endl;
    s2.append(s3); // 追加123wew
    s2.append(s3, 1, 2); // ew
    cout << s2 << endl; // 123wewew
    string sub = s2.substr(2, 3); // 字符串裁剪
    cout << sub << endl; // 3we
    s4.swap(s5); // 字符串交换,只有引用和地址才会改变外部的值
    // c_str 支持C,转换为char *
    string s = "后端码匠"; // 存储在堆区 方法执行完毕 执行析构函数 从堆区移除
    // 一般不会这样使用
    const char *s_c = s.c_str(); // 将C++ string转换为支持C的字符串,返回常量指针 指针指向了常量,不能通过指针来修改常量
    printf("%s\n", s_c);
    // 一般开发会使用strcpy拷贝,防止被销毁掉等问题 在FFmpeg是使用的C,所以在使用C++开发时必须要对C的转换
    char ss[20];
    strcpy(ss, s.c_str()); // 拷贝到一个新的变量中
    return 0;
}

kkkk 2345
123wewew
3we
后端码匠

到此这篇关于C++多态特性之派生与虚函数与模板详细介绍的文章就介绍到这了,更多相关C++派生 虚函数 模板内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ 多态虚函数的底层原理深入理解

    目录 1 多态的基本概念 1.1 什么是多态? 1.2 怎么实现多态 2 虚函数的底层原理 1 多态的基本概念 1.1 什么是多态? 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为,通常是父类调用子类的重写函数,在C++中就是 父类指针指向子类对象,此时父类指针的向下引用就可以实现多态 比如看下面的代码: class Animal { public: //虚函数 virtual void speak() { cout << "动物在说话" <<

  • C++中的多态问题—理解虚函数表及多态实现原理

    目录 一.多态的概念 概念 构成条件 二.虚函数的重写 重写的定义 重写的特殊情况 override和final关键字 区分重写.重载.重定义 抽象类的概念 三.多态的实现原理 父类对象模型 补充:生成默认构造方法的场景 子类对象模型 多态的调用原理 多继承的虚函数表 四.继承与多态中的常见问题 总结 注:编译环境为VS 2022,指针大小为4字节 一.多态的概念 概念 多态,指完成某个行为,不同的对象去完成时会产生出不同的状态.如:定一个一Animal类,类中包含动物的叫声这种方法,分别定义D

  • C++中关于多态实现和使用方法

    目录 赋值兼容 实例 多态 静多态 动多态 格式 实例 override 纯虚函数 含有虚函数的析构函数 注意事项 RTTI typeid typecast 多态实现 虚函数 一般继承(no override) 一般继承(override) 过程推断 都说 C++ 是面向对象的语言,其中的面向对象主要包括三部分:继承,封装,多态.继承和封装我们之前就简单介绍过,这里主要对多态的使用方法做一个简单说明. 赋值兼容 赋值兼容说的是在使用基类对象的地方可以使用公有继承类的对象来代替.赋值兼容是一种默认

  • C++多态的示例详解

    目录 案例一:计算器 案例要求 代码实现 运行效果 案例二:制作饮品 案例要求 代码实现 运行效果 案例三:电脑组装 案例要求 代码实现 运行效果 今天就以三个案例来把C++多态的内容结束.第一个案例就是用多态写一个计算器并实现简单的加减乘除操作:第二个案例就是一个饮品制作,主要就是抽象类重写方法:第三个是比较综合的电脑组装案例,正文会详细介绍:那么就开始上手操作吧! 案例一:计算器 案例要求 使用多态实现计算器的加减乘除操作 代码实现 class AbstractCalculator { pu

  • C++虚函数和多态超详细分析

    目录 1.什么是虚函数 2.纯虚函数 3.c++多态 4.纯虚函数和ADT过程 5.虚析构函数 6.dynamic_cast类型转换 7.成员函数指针 1.什么是虚函数 C++类中用virtual修饰的函数叫做虚函数,构造函数没有虚构造函数,存在虚析构函数,C++所有虚函数都是一个指针去存储的,所以具有虚函数的类,内存会增加一个指针大小的内存 #include<iostream> #include<string> using namespace std; class MM { pu

  • JAVA JNI函数的注册过程详细介绍

    JAVA JNI函数的注册过程详细介绍 我们在java中调用Native code的时候,一般是通过JNI来实现的,我们只需要在java类中加载本地.so库文件,并声明native方法,然后在需要调用的地方调用即可,至于java中native方法的具体实现,全部交给了Native层.我们要在java中正确地调用到本地代码中对应函数的前提是什么呢?答案就是通过一定的机制建立java中native方法和本地代码中函数的一一对应关系,那么这种机制是什么呢?就是JNI函数的注册机制. JNI函数的注册有

  • sql server数据库中raiserror函数用法的详细介绍

    sql server数据库中raiserror函数的用法 server数据库中raiserror的作用就和asp.NET中的throw new Exception一样,用于抛出一个异常或错误.这个错误可以被程序捕捉到. raiserror的常用格式如下: raiserror('错误的描述',错误的严重级别代码,错误的标识,错误的描述中的参数的值(这个可以是多个),一些其它参数),在官方上的格式描述如下: RAISERROR ( { msg_id | msg_str | @local_variab

  • Kotlin作用域函数使用示例详细介绍

    目录 1 let 2 run 3 with 4 apply 5 also 这里我们将介绍Kotlin 5个作用域函数:let,run,with,apply,also. 1 let let 可用于范围界定和空值检查.在对象上调用时,let 执行给定的代码块并返回其最后一个表达式的结果.对象可通过引用它(默认情况下)或自定义名称在块内进行访问. 所以,总结起来,let 有如下三大特征: // 重点11:使用it替代object对象去访问其公有的属性 & 方法 object.let{ it.todo(

  • java 中函数的参数传递详细介绍

    java中函数的参数传递 总结: 1.将对象(对象的引用)作为参数传递时传递的是引用(相当于指针).也就是说函数内对参数所做的修改会影响原来的对象.   2.当将基本类型或基本类型的包装集作为参数传递时,传递的是值.也就是说函数内对参数所做的修改不会影响原来的变量.   3.数组(数组引用))作为参数传递时传递的是引用(相当于指针).也就是说函数内对参数所做的修改会影响原来的数组.   4.String类型(引用)作为参数传递时传递的是引用,只是对String做出任何修改时有一个新的String

  • 深入了解C++的多态与虚函数

    目录 1.多态的机制与虚函数的机制 1.1 多态的机制 1.2 虚函数的机制 1.3虚函数表的结构图 1.4 动态多态实现的三个前提件(很重要) 2.多态实例应用 3.多态的巨大问题与虚析构 3.1代码举例说明 3.2代码实现 4.纯虚函数与抽象类 4.1纯虚函数语法格式 4.2纯虚函数的定义 4.3抽象类的应用实例 1.多态的机制与虚函数的机制 1.1 多态的机制 1.当在类中使用virtual声明一个函数为虚函数时,在编译时,编译器会自动在基类中默默地安插一个虚函数表指针,同时的.rodat

  • C++中虚函数与纯虚函数的用法

    本文较为深入的分析了C++中虚函数与纯虚函数的用法,对于学习和掌握面向对象程序设计来说是至关重要的.具体内容如下: 首先,面向对象程序设计(object-oriented programming)的核心思想是数据抽象.继承.动态绑定.通过数据抽象,可以使类的接口与实现分离,使用继承,可以更容易地定义与其他类相似但不完全相同的新类,使用动态绑定,可以在一定程度上忽略相似类的区别,而以统一的方式使用它们的对象. 虚函数的作用是实现多态性(Polymorphism),多态性是将接口与实现进行分离,采用

  • C++ 类中有虚函数(虚函数表)时 内存分布详解

    虚函数表 对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的.简称为V-Table.在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承.覆盖的问题,保证其容真实反应实际的函数.这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数. 这里我们着重看一下这张虚函数表.C++的编译器应该是

  • 浅谈C++中虚函数实现原理揭秘

    编译器到底做了什么实现的虚函数的晚绑定呢?我们来探个究竟. 编译器对每个包含虚函数的类创建一个表(称为V TA B L E).在V TA B L E中,编译器放置特定类的虚函数地址.在每个带有虚函数的类 中,编译器秘密地置一指针,称为v p o i n t e r(缩写为V P T R),指向这个对象的V TA B L E.通过基类指针做虚函数调 用时(也就是做多态调用时),编译器静态地插入取得这个V P T R,并在V TA B L E表中查找函数地址的代码,这样就能调用正确的函数使晚捆绑发生

  • C++虚函数表实例分析

    多态是C++面向对象程序设计的一个重要特性.以前看到虚函数觉得很神奇,为什么就能实现多态了呢.最初的时候曾设想,要实现运行时多态,应该让对象的某个部分始终指向一个固定的地址,子类继承的时候,就修改这个地址的内容.这样,父类和子类都是到同一个固定地址去读取内容,在运行时就能表现不同行为. 在看了<深度探索c++对象模型>之后,发现思路是类似的.在对象中,有一个指针指向一张虚函数表,里面按照次序存放了每一个虚函数,当子类继承的时候,即到虚函数表的指定位置去修改函数地址.当我们通过父类指针来操作一个

  • 深入浅析C++多态性与虚函数

    派生一个类的原因并非总是为了继承或是添加新的成员,有时是为了重新定义基类的成员,使得基类成员"获得新生".面向对象的程序设计真正的力量不仅仅是继承,而且还在于允许派生类对象像基类对象一样处理,其核心机制就是多态和动态联编. (一)多态性 多态是指同样的消息被不同的对象接收时导致不同的行为.所谓消息是指对类成员函数的调用,不同的行为是指的不同的实现,也就是调用了不同的函数. 1)多态的分类 广义上说,多态性是指一段程序能够处理多种类型对象的能力.在C++中,这种多态性可以通过重载多态(函

随机推荐