成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++高級(jí)編程:構(gòu)建高效穩(wěn)定接口與深入對(duì)象設(shè)計(jì)技巧

開(kāi)發(fā) 前端
類是C++中的主要抽象單位,你應(yīng)該將抽象原則應(yīng)用于你的類,盡可能將接口與實(shí)現(xiàn)分離。具體來(lái)說(shuō),你應(yīng)該使所有數(shù)據(jù)成員私有,并可選擇性地提供getter和setter方法。

一、建立穩(wěn)定接口

類是C++中的主要抽象單位。你應(yīng)該將抽象原則應(yīng)用于你的類,盡可能將接口與實(shí)現(xiàn)分離。具體來(lái)說(shuō),你應(yīng)該使所有數(shù)據(jù)成員私有,并可選擇性地提供getter和setter方法。這就是SpreadsheetCell類的實(shí)現(xiàn)方式:m_value是私有的,而公共的set()方法設(shè)置值,getValue()和getString()方法檢索值。

1.使用接口和實(shí)現(xiàn)類

即便采取了上述措施和最佳設(shè)計(jì)原則,C++語(yǔ)言本質(zhì)上對(duì)抽象原則不友好。其語(yǔ)法要求你將公共接口和私有(或受保護(hù)的)數(shù)據(jù)成員及方法組合在一個(gè)類定義中,從而將類的一些內(nèi)部實(shí)現(xiàn)細(xì)節(jié)暴露給其客戶端。這樣做的缺點(diǎn)是,如果你需要在類中添加新的非公開(kāi)方法或數(shù)據(jù)成員,所有使用該類的客戶端都必須重新編譯。這在大型項(xiàng)目中可能成為負(fù)擔(dān)。

好消息是你可以讓你的接口更加干凈,并隱藏所有實(shí)現(xiàn)細(xì)節(jié),從而實(shí)現(xiàn)穩(wěn)定的接口。壞消息是這需要一些編碼工作。基本原則是為你想編寫(xiě)的每個(gè)類定義兩個(gè)類:接口類和實(shí)現(xiàn)類。實(shí)現(xiàn)類與你在不采取此方法時(shí)編寫(xiě)的類相同。接口類提供與實(shí)現(xiàn)類相同的公共方法,但它只有一個(gè)數(shù)據(jù)成員:指向?qū)崿F(xiàn)類對(duì)象的指針。這被稱為pimp習(xí)語(yǔ),私有實(shí)現(xiàn)習(xí)語(yǔ),或橋接模式。接口類的方法實(shí)現(xiàn)簡(jiǎn)單地調(diào)用實(shí)現(xiàn)類對(duì)象上的等效方法。

這樣的結(jié)果是,無(wú)論實(shí)現(xiàn)如何改變,都不會(huì)影響公共接口類。這減少了重新編譯的需要。如果實(shí)現(xiàn)(僅實(shí)現(xiàn))發(fā)生變化,使用接口類的客戶端無(wú)需重新編譯。請(qǐng)注意,這種習(xí)語(yǔ)僅在單一數(shù)據(jù)成員是指向?qū)崿F(xiàn)類的指針時(shí)才有效。如果它是按值數(shù)據(jù)成員,則在實(shí)現(xiàn)類定義發(fā)生變化時(shí),客戶端必須重新編譯。

要在Spreadsheet類中使用此方法,請(qǐng)定義以下公共接口類,稱為Spreadsheet。

module;
#include <cstddef>
export module spreadsheet;
export import spreadsheet_cell;
import <memory>;

export class SpreadsheetApplication { };

export class Spreadsheet {
public:
    Spreadsheet(const SpreadsheetApplication& theApp, size_t width = MaxWidth, size_t height = MaxHeight);
    Spreadsheet(const Spreadsheet& src);
    Spreadsheet(Spreadsheet&&) noexcept;
    ~Spreadsheet();
    Spreadsheet& operator=(const Spreadsheet& rhs);
    Spreadsheet& operator=(Spreadsheet&&) noexcept;
    void setCellAt(size_t x, size_t y, const SpreadsheetCell& cell);
    SpreadsheetCell& getCellAt(size_t x, size_t y);
    size_t getId() const;
    static const size_t MaxHeight { 100 };
    static const size_t MaxWidth { 100 };
    void swap(Spreadsheet& other) noexcept;

private:
    class Impl;
    std::unique_ptr<Impl> m_impl;
};

export void swap(Spreadsheet& first, Spreadsheet& second) noexcept;

實(shí)現(xiàn)類Impl是一個(gè)私有嵌套類,因?yàn)槌薙preadsheet類之外,沒(méi)有人需要了解這個(gè)實(shí)現(xiàn)類。現(xiàn)在,Spreadsheet類只包含一個(gè)數(shù)據(jù)成員:指向Impl實(shí)例的指針。公共方法與舊的Spreadsheet類相同。

2.掌握類和對(duì)象

嵌套的Spreadsheet::Impl類在spreadsheet模塊的實(shí)現(xiàn)文件中定義。它應(yīng)該對(duì)客戶端隱藏,因此不導(dǎo)出Impl類。Spreadsheet.cpp模塊實(shí)現(xiàn)文件如下開(kāi)始:

module;
#include <cstddef

>
module spreadsheet;
import <utility>;
import <stdexcept>;
import <format>;
import <algorithm>;
using namespace std;

// Spreadsheet::Impl類定義。
class Spreadsheet::Impl {
    /* 為簡(jiǎn)潔起見(jiàn)省略 */
};

// Spreadsheet::Impl方法定義。
Spreadsheet::Impl::Impl(const SpreadsheetApplication& theApp, size_t width, size_t height)
: m_id { ms_counter++ }
, m_width { min(width, Spreadsheet::MaxWidth) }
, m_height { min(height, Spreadsheet::MaxHeight) }
, m_theApp { theApp }
{
    m_cells = new SpreadsheetCell*[m_width];
    for (size_t i{ 0 }; i < m_width; i++) {
        m_cells[i] = new SpreadsheetCell[m_height];
    }
}
// 其他方法定義省略以簡(jiǎn)潔。

Impl類幾乎具有與原始Spreadsheet類相同的接口。對(duì)于方法實(shí)現(xiàn),需要記住Impl是一個(gè)嵌套類;因此,你需要指定作用域?yàn)镾preadsheet::Impl。所以,對(duì)于構(gòu)造函數(shù),它變成了Spreadsheet::Impl::Impl(...)。

由于Spreadsheet類具有指向?qū)崿F(xiàn)類的unique_ptr,因此Spreadsheet類需要有用戶聲明的析構(gòu)函數(shù)。由于我們不需要在此析構(gòu)函數(shù)中執(zhí)行任何操作,因此可以在實(shí)現(xiàn)文件中將其默認(rèn)為:

Spreadsheet::~Spreadsheet() = default;

事實(shí)上,它必須在實(shí)現(xiàn)文件中默認(rèn),而不是直接在類定義中。原因是Impl類僅在Spreadsheet類定義中前向聲明;也就是說(shuō),編譯器知道將會(huì)有一個(gè)Spreadsheet::Impl類出現(xiàn)在某處,但此時(shí)它還不知道定義。因此,你不能在類定義中默認(rèn)析構(gòu)函數(shù),因?yàn)榫幾g器會(huì)嘗試使用尚未定義的Impl類的析構(gòu)函數(shù)。在這種情況下,對(duì)其他方法進(jìn)行默認(rèn)操作時(shí)也是如此,例如移動(dòng)構(gòu)造函數(shù)和移動(dòng)賦值運(yùn)算符。

二、實(shí)現(xiàn)Spreadsheet方法

Spreadsheet類的方法實(shí)現(xiàn),如setCellAt()和getCellAt(),只是將請(qǐng)求傳遞給底層的Impl對(duì)象:

void Spreadsheet::setCellAt(size_t x, size_t y, const SpreadsheetCell& cell) {
    m_impl->setCellAt(x, y, cell);
}

SpreadsheetCell& Spreadsheet::getCellAt(size_t x, size_t y) {
    return m_impl->getCellAt(x, y);
}

Spreadsheet的構(gòu)造函數(shù)必須構(gòu)造一個(gè)新的Impl以執(zhí)行其工作:

Spreadsheet::Spreadsheet(const SpreadsheetApplication& theApp, size_t width, size_t height) {
    m_impl = make_unique<Impl>(theApp, width, height);
}

Spreadsheet::Spreadsheet(const Spreadsheet& src) {
    m_impl = make_unique<Impl>(*src.m_impl);
}

拷貝構(gòu)造函數(shù)看起來(lái)有些奇怪,因?yàn)樗枰獜脑碨preadsheet復(fù)制底層的Impl。拷貝構(gòu)造函數(shù)接受一個(gè)Impl的引用,而不是指針,所以你必須解引用m_impl指針來(lái)獲取對(duì)象本身。

Spreadsheet賦值運(yùn)算符必須同樣將賦值傳遞給底層的Impl:

Spreadsheet& Spreadsheet::operator=(const Spreadsheet& rhs) {
    *m_impl = *rhs.m_impl;
    return *this;
}

賦值運(yùn)算符中的第一行看起來(lái)有些奇怪。Spreadsheet賦值運(yùn)算符需要將調(diào)用轉(zhuǎn)發(fā)給Impl賦值運(yùn)算符,這只在你復(fù)制直接對(duì)象時(shí)運(yùn)行。通過(guò)解引用m_impl指針,你強(qiáng)制執(zhí)行直接對(duì)象賦值,這導(dǎo)致調(diào)用Impl的賦值運(yùn)算符。

swap()方法簡(jiǎn)單地交換單一數(shù)據(jù)成員:

void Spreadsheet::swap(Spreadsheet& other) noexcept {
    std::swap(m_impl, other.m_impl);
}

這種技術(shù)將接口與實(shí)現(xiàn)真正分離,是非常強(qiáng)大的。雖然一開(kāi)始有些笨拙,但一旦習(xí)慣了,你會(huì)發(fā)現(xiàn)它很自然易用。然而,在大多數(shù)工作環(huán)境中,這不是常見(jiàn)做法,所以你可能會(huì)遇到同事的一些抵觸。支持這種做法的最有力論據(jù)不是分離接口的美學(xué),而是如果類的實(shí)現(xiàn)發(fā)生變化,構(gòu)建時(shí)間的加速。

三、注意

使用穩(wěn)定的接口類,可以減少構(gòu)建時(shí)間。將實(shí)現(xiàn)與接口分離的另一種方法是使用抽象接口,即只有純虛方法的接口,然后有一個(gè)實(shí)現(xiàn)該接口的實(shí)現(xiàn)類。這是下個(gè)主題。

責(zé)任編輯:趙寧寧 來(lái)源: coding日記
相關(guān)推薦

2010-01-11 10:28:51

C++編程

2024-01-03 13:38:00

C++面向?qū)ο缶幊?/a>OOP

2010-01-12 15:24:48

C++語(yǔ)言

2011-05-30 15:29:32

C++

2010-01-26 17:11:13

C++編程

2024-04-01 13:05:13

C++接口類開(kāi)發(fā)

2011-07-10 15:26:54

C++

2024-01-22 00:10:00

C++接口編程

2011-07-13 16:36:11

C++

2024-09-24 10:41:57

MyBatis編程

2010-01-11 10:41:05

C++編程

2010-01-12 10:40:22

C++程序員

2023-11-22 13:40:17

C++函數(shù)

2012-12-25 09:45:08

PythonWeb

2025-04-02 03:11:00

Python函數(shù)C++

2025-01-27 00:54:31

2023-12-13 10:01:15

數(shù)據(jù)結(jié)構(gòu)c++編程

2010-01-13 10:16:42

C++軟件

2010-01-28 16:05:09

C++風(fēng)格與技巧

2024-01-22 13:05:00

C++編程異常處理
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 蜜臀网| 中文字幕专区 | 精品中文字幕一区二区 | 亚洲欧美一区二区三区视频 | 日本视频在线播放 | 日本亚洲精品 | 黄色国产视频 | 婷婷在线免费 | 亚洲天天干 | 亚洲一区二区三区欧美 | 亚洲成人在线网 | 精品成人在线观看 | 五月婷亚洲 | 亚洲欧美中文日韩在线v日本 | 免费av一区二区三区 | 亚洲欧洲中文 | 中文字幕二区 | 欧美区日韩区 | 国产精品视频999 | 欧美一区二区三区在线视频 | 青青久久| 天天干视频网 | 99久久久国产精品 | 日韩免费网 | 欧美天堂在线 | 欧美日日| 福利视频网址 | 91精品久久久久久久久久小网站 | 毛片a | 亚洲精品免费在线观看 | 欧美 视频 | 亚洲视频欧美视频 | 日韩一区二区三区视频在线播放 | 久久久69 | 午夜精品在线观看 | 中文字幕高清av | 亚洲一区二区精品视频 | 亚洲情视频 | 免费在线观看av的网站 | 999久久久 | 国产精品福利在线观看 |