复制(copy) 和 虚复制(virtual copy) 的 区别

本文地址: http://blog.csdn.net/caroline_wendy/article/details/16120397

在继承过程中, 需要区分复制(copy)虚复制(virtual copy);

在派生类转换为基类时, 复制(copy)有可能切掉(sliced down)派生对象的派生部分, 只保留基类部分, 使派生类的虚函数无法使用;

为了避免此情况, 如果传入是对象, 则可以定义虚函数clone, 使派生类继承此虚函数, 再传入容器, 可以重载方法;

另外, 如果传入是实参, 使用shared_ptr<Base>配合make_shared<Derived>添加容器, 也可以进行动态绑定;

再传入容器中, 容器会自动调用派生类的重载方法, 实现动态绑定;

注意: 引用限定符(reference qualifier) GCC 4.8.1 才能支持;

代码:

/*
* CppPrimer.cpp
*
* Created on: 2013.11.12
* Author: Caroline
*/ /*eclipse cdt*/ #include <iostream>
#include <string>
#include <vector>
#include <set> #include <utility>
#include <memory>
#include <cstddef> using namespace std; class Quote; class Quote {
public:
Quote() = default;
Quote (const std::string& book, double sales_price) :
bookNo (book), price (sales_price) {}
void add_item (const Quote& sale);
std::string isbn() const { return bookNo; }
virtual double net_price (std::size_t n) const { return n* price; } //虚函数
virtual Quote* clone() const & {return new Quote(*this);}
virtual Quote* clone() && {return new Quote(std::move(*this));}
virtual ~Quote() = default; //动态绑定析构器
private:
std::string bookNo;
protected: //受保护类型
double price = 0.0;
}; class Disc_quote : public Quote { //抽象基类
public:
Disc_quote() = default;
Disc_quote (const std::string& book, double price, std::size_t qty, double disc) :
Quote(book, price), quantity (qty), discount (disc) {}
double net_price (std::size_t) const = 0; //纯虚函数
protected:
std::size_t quantity = 0;
double discount = 0.0;
}; class Bulk_quote final : public Disc_quote { //final限定词, 无法被继承
public:
Bulk_quote() = default;
Bulk_quote(const std::string& book, double p, std::size_t qty, double disc) :
Disc_quote(book, p, qty, disc) {} //使用基类的构造器
double net_price(std::size_t cnt) const override;
virtual Bulk_quote* clone() const & {return new Bulk_quote(*this);}
virtual Bulk_quote* clone() && {return new Bulk_quote(std::move(*this));}
}; double Bulk_quote::net_price(std::size_t cnt) const
{
if (cnt >= quantity)
return cnt * (1-discount) * price;
else
return cnt * price;
} double print_total(std::ostream &os, const Quote& item, std::size_t n)
{
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << std::endl;
return ret;
} class Basket {
public:
void add_item (const std::shared_ptr<Quote> &sale) { items.insert(sale); }
void add_item (const Quote& sale)
{
//items.insert(std::shared_ptr<Quote>(new Quote(sale))); //不会动态绑定
items.insert(std::shared_ptr<Quote>(sale.clone()));
}
void add_item (Quote&& sale)
{
//items.insert(std::shared_ptr<Quote>(new Quote(std::move(sale)))); //不会动态绑定
items.insert(std::shared_ptr<Quote>(std::move(sale).clone()));
}
double total_reciept (std::ostream&) const;
private:
static bool compare (const std::shared_ptr<Quote> &lhs,
const std::shared_ptr<Quote> &rhs)
{ return lhs->isbn() < rhs->isbn(); };
std::multiset<std::shared_ptr<Quote>, decltype(compare)*> items{compare};
}; double Basket::total_reciept(std::ostream &os) const
{
double sum = 0.0;
for(auto iter = items.cbegin(); iter != items.cend();
iter = items.upper_bound(*iter)) { //跳过同名书, 直接计算count
sum += print_total(os, **iter, items.count(*iter)); //*it是shared_ptr; **it是object
}
os << "Total Sale: " << sum << std::endl;
return sum;
} int main (void) { Basket bsk;
/*bsk.add_item(std::make_shared<Quote>("CppPrimer", 45));
bsk.add_item(std::make_shared<Bulk_quote>("EffectiveCpp", 50, 2, 0.15));
bsk.add_item(std::make_shared<Bulk_quote>("EffectiveCpp", 50, 2, 0.15));
bsk.add_item(std::make_shared<Bulk_quote>("EffectiveCpp", 50, 2, 0.15));*/ bsk.add_item(Quote("CppPrimer", 45));
bsk.add_item(Bulk_quote("EffectiveCpp", 50, 2, 0.15));
bsk.add_item(Bulk_quote("EffectiveCpp", 50, 2, 0.15));
bsk.add_item(Bulk_quote("EffectiveCpp", 50, 2, 0.15)); bsk.total_reciept(std::cout); return 0; }

输出:

ISBN: CppPrimer # sold: 1 total due: 45
ISBN: EffectiveCpp # sold: 3 total due: 127.5
Total Sale: 172.5

C++ - 复制(copy) 和 虚复制(virtual copy) 的 区别的更多相关文章

  1. iOS-深复制(mutableCopy)与浅复制(copy)

    浅复制:只复制指向对象的指针,而不复制引用对象本身.对于浅复制来说,A和A_copy指向的是同一个内存资源,复制的只是一个指针,对象本身资源还是只有一份(对象引用计数+1),那如果我们对A_copy执 ...

  2. cmd copy命令 文件复制【转】

    本文转载自:https://www.jb51.net/article/18981.htm copy,中文含义为“复制”,一个很容易见名知意的命令,它的作用是复制文件,用法十分简单:copy 源文件 目 ...

  3. PHP通过copy()函数来复制一个文件

    PHP通过copy()函数来复制一个文件.用法如下: bool copy(string $source, string $dest) 其中$source是源文件的路径,$dest是目的文件的路径.函数 ...

  4. 工作总结 1 sql写法 insert into select from 2 vs中 obj文件和bin文件 3 npoi 模板copy CopySheet 最好先全部Copy完后 再根据生成sheet写数据 4 sheet.CopyRow(rowsindex, rowsindex + x); 5 npoi 复制模板如果出现单元格显示问题

    我们可以从一个表中复制所有的列插入到另一个已存在的表中: INSERT INTO table2SELECT * FROM table1; 或者我们可以只复制希望的列插入到另一个已存在的表中: INSE ...

  5. Eclipse中Copy Qualified Name复制类全名解决办法

    Eclipse中用Copy Qualified Name复制类全名时总是这样的/struts1/src/me/edu/HelloAction.java很不方便可以这样解决下载下边插件解压到Eclips ...

  6. 【转载】C#通过Copy方法快速复制DataTable对象

    C#中的Datatable数据变量的操作过程中,可以通过DataTable的Copy方法快速复制当前的DataTable变量到新对象中,复制数据包含当前DataTable的结构信息如列名,同时也包含当 ...

  7. C++虚复制构造函数,设置Clone()方法返回基类指针,并设置为虚函数

    构造函数不能是虚函数.但有时候确实需要能传递一个指向基类对象的指针,并且有已创建的派生类对象的拷贝.通常在类内部创建一个Clone()方法,并设置为虚函数. //Listing 12.11 Virtu ...

  8. Java中的深拷贝(深复制)和浅拷贝(浅复制)

    深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复 ...

  9. c++中深层复制(浅层复制运行错误)成功运行-----sample

    下面随笔给出c++中深层复制(浅层复制运行错误)成功运行------sample. 浅层复制与深层复制 浅层复制 实现对象间数据元素的一一对应复制. 深层复制 当被复制的对象数据成员是指针类型时,不是 ...

随机推荐

  1. Android内部自带的SQLite数据库操作dos命令

    1:什么叫做SQLite数据库 Android系统内核是Linux系统,Android系统很特殊,他自带了一个SQLite数据库,轻量型的一款嵌入式的数据库 它占用资源非常的低,在嵌入式设备中,可能只 ...

  2. Oracle 去除两边空格

    sql 去掉两头空格sql语法中没有直接去除两头空格的函数,但有ltrim()去除左空格rtrim()去除右空格.合起来用就是sql的trim()函数,即select ltrim(rtrim(UsrN ...

  3. WCF use ProtoBuf

    ProtoBuf, 比起xml和json, 传输的数据里面没有自描述标签, 而且是基于二进制的, 所以有着超高的传输效率, 据牛人张善友的描述, 可以替代WCF的自带的编码方案, 效率有极大的提升. ...

  4. java多线程详解(1)-多线程入门

    一.多线程的概念 线程概念 线程就是程序中单独顺序的流控制. 线程本身不能运行,它只能用于程序中. 说明:线程是程序内的顺序控制流,只能使用分配给程序的资源和环境. 进程:操作系统中执行的程序 程序是 ...

  5. Quartz.net 定时调度CronTrigger时间配置格式说明

    1.   CronTrigger时间格式配置说明 CronTrigger配置格式: 格式: [秒] [分] [小时] [日] [月] [周] [年] 序号 说明 是否必填 允许填写的值 允许的通配符 ...

  6. 新的框架,新的感觉ASP.NET MVC 分享一个简单快速适合新手的框架

    在ASP.NET世界中摸爬滚打好几年,用过了各种框架,在最初的ASP.NET web from 到现在的MVC 在起初的经典三层,到现在的MVC  IOC  注入 . 突然发现,有些时候真不是跟风用一 ...

  7. JSP目录

    JSP目录   课时1    jsp概述和背后原理31:11 课时2    三种jsp的scriptlet语法27:29 课时3    jsp的注释14:00 课时4    JSP4个域对象的作用域3 ...

  8. VS2012开发工具BUG

    发现VS2012开发工具 新建立项目名称长度限制的一个bug, 向导方式名称长度限制56个,但建立好的项目名称长度是可以改的很长很长. 也有想是不是生成程序集的名称会有限制,同样这里生成程序集名称,及 ...

  9. JAVA多线程 问题 转载

    参考:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/ http://www.cn ...

  10. C#中指针的用法

    (*) unsafe 和 fixed unsafe { ]; ; i < array.Length; i++) { array[i] = i; } fixed (int* p = array) ...