第15章 面向对象程序设计

面向对象的核心是:数据抽象、继承、动态绑定

数据抽象:将类的接口与实现分离

继承:对类型的相似关系进行定义建模

动态绑定:忽略相似类的区别,统一使用它们的对象

15.2基类与派生类

class Base
{
public:
    Base() = default;
    Base(int value) :value(value){}
    virtual int get_value() { return value; };
    virtual ~Base() = default;
private:
    int value;
protected:
    void change_value() { value++; }
};

基类都应该定义一个虚函数,这样在delete一个指向派生类对象的基类指针所指向new分配的空间时,能会有理想的析构函数调用(先调用派生类的析构函数,再调用基类的。否则将会仅调用基类的析构函数)。

class Derived final:public Base
{
public:
    Derived() = default;
    Derived(int value) :Base(value) {}
    int get_value() override { return value*value; }
};

派生类覆盖基类的虚函数,可以使用(不必须,旧标准没有)override关键字,同时派生类的此函数自动成为virtual的,不管加不加virtual关键字。

final表明这个类不能被继承。

如果需要喜用被override的基类成员,需要加上基类的作用域Base::

15.2.3类型转换与继承

  1. 派生类的指针或引用可以隐式转换成基类的指针引用,反之则不行。
  2. 派生类的对象和基类的对象之间不存在期望的类型转换,因为派生类赋值给基类的时候,实际发生的是执行拷贝构造函数等过程,最终得到一个新的基类对象。

15.3虚函数/抽象基类

我们如果想调用被override的虚函数,可以使用作用域运算符进行调用。

如果虚函数=0,就是纯虚函数。有纯虚函数的类是抽象基类。我们不能创建抽象基类的对象。

15.5访问控制与继承

protect

protect成员对类的用户来讲是不可访问的

派生类protect继承基类,则基类的public成员降维成protect成员存在于派生类中

派生类的成员可以通过派生类的对象访问基类的protect成员(因为2中继承过来,相当于自己的protect成员),而不能通过基类的对象访问基类的protect成员(因为1)

private

private成员对用类的用户来讲是不可访问的。private继承过来的基类的所有成员在派生类中都将会是私有的。

派生类public继承的基类之间,才能够进行类型转换

提升基类成员的访问级别

class Base {
public:
    std::size_t size() const { return n; }
protected:
    std::size_t n;
};
class Derived : private Base {
public:
    //本来对于使用者是private的,但是提升到了public
    using Base::size;
protected:
    //本来对于使用者是private的,但是提升到了protected
    using Base::n;
};

15.6继承中类的作用域

在对象进行成员访问的时候,首先从其静态作用域中需要成员。如果找不到,去外层基类中进行查找。

如果派生类定义了和基类中名字相同的成员,则基类的成员在派生类的作用域中将会被隐藏。如果要使用,则可以通过基类的作用域进行调用。

15.7构造函数与拷贝控制

基类为虚析构函数时,使用基类的指针或引用删除(delete)派生类对象时,才能正确执行派生类的析构函数。

基类的虚析构函数(哪怕=default)还会阻止合成的移动操作。(析构函数一般和合成的移动操作有冲突)所以派生类已没有合成的移动操作,一般应该重新定义如下:

class Quote {
public:
    Quote() = default;  // memberwise default initialize
    Quote(const Quote&) = default; // memberwise copy
    Quote(Quote&&) = default;  // memberwise copy
    Quote&operator=(const Quote&) = default; // copy assign
    Quote&operator=(Quote&&) = default;  // move assign
    virtual~Quote() = default;
    // other members as before
};

15.7.4继承的构造函数

默认、拷贝、移动构造函数将不会被继承。

class Base
{
public:
     Base(int n) { cout << "base" << endl; }
};
class Derived final:public Base
{
public:
    using Base::Base;
    //上边这个继承的基类构造函数会被编译器产生如下代码
    //但是如果用户自定义了,基类的构造函数就会被覆盖
    //Derived(int n) :Base(n) { cout << "derived" << endl; }
};
时间: 2024-12-06 02:39:27

第15章 面向对象程序设计的相关文章

C++ Primer学习总结 第15章 面向对象程序设计

第15章 面向对象程序设计 1.    构造基类和派生类. 其中A类是基类,B类是派生类.派生类的构造函数必须重新写过,不能继承.(因为毕竟两个类的类名都不一样,不可能构造函数继承)只继承其他的成员函数和成员变量. 派生类可以覆盖基类的虚函数,但是也可以选择不覆盖(即直接使用父类的函数版本)比例A类的print_1()虚函数就没有被覆盖. 基类的静态成员:如果基类有一个静态成员,那么基类和所有派生类都共同拥有这仅有的一个静态成员. 2.    基类的虚函数默认实参最好与派生类的虚函数默认实参一致

第7章 面向对象程序设计

第7章 面向对象程序设计 7.1 面向对象概述 面向对象(Object Oriented)的英文缩写是OO,它是一种设计思想.从20世纪60年代提出面向对象的概念到现在,它已经发展成为一种比较成熟的编辑思想,并且逐步成为目前软件开发领域的主流计技术.如我们经常听说的面向对象编程(Object Oriented Programming,即OOP)就是主要针对大型软件设计而提出的,它可以使软件设计更加灵活,并且能更好地进行代码复用. 面向对象中的对象(Object),通常是指客观世界中存在的对象,具

JavaScript高级程序设计 第六章 面向对象程序设计

面向对象程序设计 ECMA-262将对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”严格来讲,这就相当于说对象是一组没有特定顺序的值.对象的每个属性和方法都有一个名字,而每个名字都映射到一个值. 6.1理解对象 创建对象的最简单方式就是创造一个Object实例,然后再为它添加属性和方法,如下所示: var person = new Object(); person.name = 'yyg'; person.age = 23; person.job = 'student; pe

JavaScript高级程序设计学习笔记第六章--面向对象程序设计

1.ECMAScript没有类的概念,ECMA-262 把对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”,有点类似于散列表 2.ECMAScript 中有两种属性:数据属性和访问器属性. 数据属性: [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性. [[Enumerable]]:表示能否通过 for-in 循环返回属性. [[Writable]]:表示能否修改属性的值. [[Valu

第十五章 面向对象程序设计 习题

15.3 1 class Quote 2 { 3 public 4 Quote()=default; 5 Quote(const std::string &book,double sales_price):bookNo(book), 6 price(sales_price){};//类的初始化 7 8 std::string isbn() const {return bookNo;} 9 10 virtual double net_price(std::size_t n) const 11 {r

第十五章 面向对象程序设计

15.1 虚函数:基类的成员函数,并在其前面添加关键字virtual,此类函数是基类希望其派生类进行覆盖的函数 15.2 protected:对应受保护成员,派生类可以访问该成员,但其他用户则禁止访问该成员 15.3 1 class Quote { 2 public: 3 Quote() = default; 4 Quote(const string &book, double sales_price): bookNo(book), price(sales_price) {} 5 string

高程第六章--面向对象程序设计--属性类型

ES有两种属性类型:数据属性和访问器属性. 一.数据属性4个描述其行为的特性. 1:[[Configurable]]:表示能否通过delete删除属性从而重新定义属性. 2: [[Enumerable]]:表示能否通过for-in循环返回属性 3: [[Writable]]:表示能否修改属性的值 4:[[Value]]:包含这个属性的属性值 要修改属性默认的特性,必须使用ES5的defineProperty()方法 //"use strict"; var person = {}; Ob

《JavaScript高级程序设计》第6章 面向对象程序设计

6.1 对象属性 6.1.1 属性类型 1. 数据属性 我们一般所说的属性就是数据属性,它用来将一个字符串名称映射到某个值上 数据属性的4个特性: configurable, enumerable, writable, value要修改属性默认的特性,必须使用Object.defineProperty()方法Object.defineProperty(对象,属性名,描述符对象) var person = {}; Object.defineProperty(person, 'name', { wr

《C++Primer》14、15章

第14章 重载运算符与类型转换 14.1 基本概念 只有当操作的含义对于用户来说清晰明了时才使用运算符. 选择作为成员还是非成员? 赋值.下标.调用和成员访问运算符必须是成员. 复合赋值运算符一般是成员. 改变对象状态或者与给定类型密切相关的,如递增.解引用通常是成员. 具有对称性的运算符可能转换任意一端元素的运算对象,例如算数.相等.关系和位运算等,通常是非成员函数. 14.2 输入输出运算符(略) 14.3 算术与关系运算符(略) 14.4 赋值运算符(略) 14.5 下标运算符 通常会定义