答:
void *operator new(size_t size){
if (void *mem = malloc(size)) {
return mem;
} else {
throw std::bad_alloc();
}
}
void operator delete(void *mem) noexcept { free(mem); }
答:
#define _SCL_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdlib>
#include <new>
#include <string>
#include <memory>
using namespace std;
void *operator new(size_t size){
if (void *mem = malloc(size)) {
cout << "In operator new " << endl;
return mem;
} else {
throw std::bad_alloc();
}
}
void operator delete(void *mem) noexcept {
cout << "In operator delete " << endl;
free(mem);
}
// 类似vector类内存分配策略的简化实现
class StrVec {
public:
StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {} //allocator 成员进行默认初始化
StrVec(const StrVec&); // 拷贝构造函数
StrVec &operator=(const StrVec&); // 拷贝赋值运算符
~StrVec(); // 析构函数
void push_back(const string&); // 拷贝元素
size_t size() const { return first_free - elements; }
size_t capacity() const { return cap - elements; }
string *begin() const { return elements; }
string *end() const { return first_free; }
private:
allocator<string> alloc; // 分配元素
// 被添加元素的函数所使用
void chk_n_alloc() { if (size() == capacity()) reallocate(); }
// 工具函数,被拷贝构造函数、赋值运算符和析构函数所使用
pair<string*, string*> alloc_n_copy(const string*, const string*);
void free(); // 销毁元素并释放内存
void reallocate(); // 获得更多内存并拷贝已有元素
string *elements; // 指向数组首元素的指针
string *first_free; // 指向数组第一个空闲元素的指针
string *cap; // 指向数组尾后位置的指针
};
void StrVec::push_back(const string& s) {
chk_n_alloc(); // 确保有空间容纳新元素
// 在 first_free 指向的元素中构造 s 的副本
alloc.construct(first_free++, s);
}
pair<string*, string*> StrVec::alloc_n_copy(const string *b, const string *e) {
// 分配空间保存给定范围中的元素
auto data = alloc.allocate(e - b);
// 初始化并返回一个 pair,该 pair 由 data 和 uninitialized_copy 的返回值构成
return{ data, uninitialized_copy(b, e , data) };
}
void StrVec::free() {
// 不能传递给deallocate一个空指针,如果elements为0,函数什么也不做
if (elements) {
// 逆序销毁旧元素
for (auto p = first_free; p != elements; /* 空 */) {
alloc.destroy(--p);
}
alloc.deallocate(elements, cap - elements);
}
}
StrVec::StrVec(const StrVec &s) {
// 调用 alloc_n_copy分配空间以容纳与 s 中一样多的元素
auto newdata = alloc_n_copy(s.begin(), s.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
StrVec::~StrVec() { free(); }
StrVec &StrVec::operator=(const StrVec &rhs) {
// 调用 alloc_n_copy分配内存,大小与rhs中元素占用空间一样多
auto data = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
void StrVec::reallocate() {
// 我们将分配当前大小两倍的内存空间
auto newcapacity = size() ? 2 * size() : 1;
// 分配新内存
auto newdata = alloc.allocate(newcapacity);
// 将数据从旧内存移动到新内存
auto dest = newdata; // 指向新数组中下一个空闲位置
auto elem = elements; // 指向旧数组中下一个元素
for (size_t i = 0; i != size(); ++i) {
alloc.construct(dest++, move(*elem++));
}
free(); // 一旦我们移动完元素就释放旧内存空间
// 更新我们的数据结构,执行新元素
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
int main() {
StrVec v;
v.push_back("Hello");
v.push_back("World");
for (auto i = v.begin(); i != v.end(); ++i) {
cout << *i << endl;
}
system("pause");
return 0;
}
class A { /* . . . */ };
class B : public A { /* . . . */ };
class C : public B { /* . . . */ };
class D : public B, public A { /* . . . */ };
(a) A *pa = new C;
B *pb = dynamic_cast< B* >(pa);
(b) B *pb = new B;
C *pc = dynamic_cast< C* >(pb);
(c) A *pa = new D;
B *pb = dynamic_cast< B* >(pa);
答:
if (C *pc = dynamic_cast< C* >(pa))
// 使用 c 的成员
} else {
// 使用 A 的成员
}
答:
try {
C& rc = dynamic_cast<C&>(*pa);
// 使用C的成员
} catch (const std::bad_cast &e) {
std::cout << e.what() << std::endl;
}
答:
答:
Query_base* Query_basePtr = new AndQuery({ "" }, { "" }); // 实际指向AndQuery对象的Query_base类型指针
// 尝试将基类Query_base指针转换为派生类AndQuery的指针
AndQuery* AndQueryPtr = dynamic_cast<AndQuery*>(Query_basePtr);
if (AndQueryPtr) {
std::cout << "Conversion to AndQuery succeed.\n";
} else {
std::cout << "Conversion to AndQuery failed.\n";
}
Query_base* Query_basePtr_2 = new OrQuery({ "" }, { "" }); // 实际指向OrQuery对象的Query_base类型指针
// 尝试将基类Query_base指针转换为派生类AndQuery的指针
AndQuery* AndQueryPtr_2 = dynamic_cast<AndQuery*>(Query_basePtr_2);
if (AndQueryPtr_2) {
std::cout << "Conversion to AndQuery succeed.\n";
} else {
std::cout << "Conversion to AndQuery failed.\n";
}
答:
Query_base* Query_basePtr = new AndQuery({ "" }, { "" }); // 实际指向AndQuery对象的Query_base类型指针
try {
AndQuery& AndQueryRef = dynamic_cast<AndQuery&>(*Query_basePtr);
std::cout << "Conversion to AndQuery succeed.\n";
} catch (const std::bad_cast&) {
std::cout << "Conversion to AndQuery failed.\n";
}
Query_base* Query_basePtr_2 = new OrQuery({ "" }, { "" }); // 实际指向OrQuery对象的Query_base类型指针
try {
AndQuery& AndQueryRef = dynamic_cast<AndQuery&>(*Query_basePtr_2);
std::cout << "Conversion to AndQuery succeed.\n";
} catch (const std::bad_cast&) {
std::cout << "Conversion to AndQuery failed.\n";
}
答:
Query_base* Query_basePtr = new AndQuery({ "" }, { "" });
Query_base* Query_basePtr_2 = new AndQuery({ "" }, { "" });
if (typeid(*Query_basePtr) != typeid(*Query_basePtr_2)) {
std::cout << "Does not refer to the same type.\n";
} else if(typeid(*Query_basePtr)== typeid(AndQuery)){
std::cout << "The type is AndQuery.\n";
} else {
std::cout << "refer to the same type, but the type is not AndQuery.\n";
}
答:
int arr[10];
Derived d;
Base *p = &d;
std::cout << typeid(42).name() << ", "
<< typeid(arr).name() << ", "
<< typeid(Sales_data).name() << ", "
<< typeid(std::string).name() << ", "
<< typeid(p).name() << ", "
<< typeid(*p).name() << std::endl;
class A { /* . . . */ };
class B : public A { /* . . . */ };
class C : public B { /* . . . */ };
(a) A *pa = new C;
cout << typeid(pa).name() << endl;
(b) C cobj;
A& ra = cobj; cout << typeid(&ra).name() << endl;
(c) B *px = new B;
A& ra = *px; cout << typeid(ra).name() << endl;
答:
答:
答:
class Screen {
public:
typedef std::string::size_type pos;
// 添加的成员函数,用于返回指向cursor成员的指针
static pos Screen::* getCursorPtr() {
return &Screen::cursor;
}
private:
pos cursor;
};
int main() {
Screen::pos Screen::* cursorPtr = Screen::getCursorPtr();
return 0;
}
答:
std::string Sales_data::* bookNoPtr;
auto pmf = &Screen::get_cursor;
pmf = &Screen::get;
答:
答:
答:
答:
// 为get_cursor函数定义类型别名
using GetCursorAction = char (Screen::*)() const;
// 为get函数定义类型别名
using GetAction = char (Screen::*)() const;
// 为get(pos, pos)函数定义类型别名
using GetPosAction = char (Screen::*)(pos, pos) const;
答:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // 包含 count_if
// 函数:统计 vector 中空字符串的数量
size_t countEmptyStrings(const std::vector<std::string>& vec) {
// 使用 lambda 表达式作为 count_if 的条件
return std::count_if(vec.begin(), vec.end(),
[](const std::string& s) { return s.empty(); });
}
int main() {
// 示例:创建一个包含空字符串的 vector
std::vector<std::string> strings = {"hello", "", "world", "", ""};
// 调用函数并打印结果
size_t count = countEmptyStrings(strings);
std::cout << "Number of empty strings: " << count << std::endl;
return 0;
}
答:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
// Sales_data 结构的定义
struct Sales_data {
Sales_data() = default;
Sales_data(const std::string &s) : bookNo(s) {}
Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p * n) {}
std::string isbn() const { return bookNo; }
double avg_price() const {
if (units_sold) {
return revenue / units_sold;
} else {
return 0;
}
}
private:
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
// 函数:找出第一个平均价格高于给定值的 Sales_data
Sales_data findFirstHighPrice(const std::vector<Sales_data>& vec, double price) {
auto it = std::find_if(vec.begin(), vec.end(), [price](const Sales_data& data) {
return data.avg_price() > price;
});
if (it != vec.end()) {
return *it; // 返回找到的元素
} else {
// 如果没有找到,返回一个默认的 Sales_data
return Sales_data();
}
}
int main() {
// 测试数据
std::vector<Sales_data> sales = {
Sales_data("Book1", 10, 20.5),
Sales_data("Book2", 5, 22.3),
Sales_data("Book3", 2, 50.0)
};
// 查找平均价格大于40的第一个 Sales_data 对象
Sales_data result = findFirstHighPrice(sales, 40.0);
if (result.isbn() != "") {
std::cout << "Found: " << result.isbn() << " with avg price: " << result.avg_price() << std::endl;
} else {
std::cout << "No Sales_data found with avg price > 40.0" << std::endl;
}
system("pause");
return 0;
}
答:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <memory>
using namespace std;
class TextQuery {
public:
class QueryResult;
using line_no = vector<string>::size_type;
TextQuery(ifstream&);
QueryResult query(const string&) const;
private:
shared_ptr<vector<string>> file; // 输入文件
// 每个单词到它所在的行号的集合的映射
map<string, shared_ptr<set<line_no>>> wm;
};
class TextQuery::QueryResult {
friend std::ostream& print(std::ostream&, const QueryResult&);
public:
QueryResult(string s, shared_ptr<set<line_no>> p,
shared_ptr<vector<string>> f) : sought(s), lines(p), file(f) { }
private:
string sought; // 查询单词
shared_ptr<set<line_no>> lines; // 出现的行号
shared_ptr<vector<string>> file; // 输入文件
};
// 读取输入文件并建立单词到行号的映射
TextQuery::TextQuery(ifstream &is) : file(new vector<string>) {
string text;
while (getline(is, text)) { // 对文件中每一行
file->push_back(text); // 保存此行文本
int n = file->size() - 1; // 当前行号
istringstream line(text); // 将行文本分解为单词
string word;
while (line >> word) { // 对行中每个单词
// 如果单词不在 wm中,以之为下标在wm中添加一项
auto &lines = wm[word]; // lines 是一个 shared_ptr
if (!lines) // 在我们第一次遇到这个单词时,此指针为空
lines.reset(new set<line_no>); // 分配一个新的 set
lines->insert(n); // 将此行号插入 set 中
}
}
}
TextQuery::QueryResult TextQuery::query(const string &sought) const {
// 如果未找到 sought,我们将返回一个指向此 set 的指针
static shared_ptr<set<line_no>> nodata(new set<line_no>);
// 使用 find 而不是下标运算符来查找单词,避免将单词添加到 wm 中!
auto loc = wm.find(sought);
if (loc == wm.end()) {
return QueryResult(sought, nodata, file); // 未找到
} else {
return QueryResult(sought, loc->second, file);
}
}
ostream &print(ostream & os, const TextQuery::QueryResult &qr) {
// 如果找到了单词,打印出现次数和所有出现的位置
os << qr.sought << " occurs " << qr.lines->size() << " " << "times" << endl;
// 打印单词出现的每一行
for (auto num : *qr.lines) { // 对 set 中每个单词
// 避免行号从 0 开始给用户带来的困惑
os << "\t(line " << num + 1 << ") " << *(qr.file->begin() + num) << endl;
}
return os;
}
void runQueries(ifstream &infile) {
// infile是一个ifstream,指向我们要处理的文件
TextQuery tq(infile); // 保存文件并建立查询 map
// 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
while (true) {
cout << "enter word to look for, or q to quit: ";
string s;
// 若遇到文件尾或用户输入了'q' 时循环终止
if (!(cin >> s) || s == "q") break;
// 指向查询并打印结果
print(cout, tq.query(s)) << endl;
}
}
int main() {
ifstream ifs("example.txt");
runQueries(ifs);
system("pause");
return 0;
}
答:
#include <iostream>
#include <string>
using namespace std;
class Token {
public:
// 因为union含有一个string成员,所以Token必须定义拷贝控制成员
Token() : tok(INT), ival{ 0 } { }
Token(const Token &t) : tok(t.tok) { copyUnion(t); }
Token &operator=(const Token&);
// 如果 union 含有一个 string成员,则我们必须销毁它
~Token() { if (tok == STR) sval.~string(); }
// 下面的赋值运算符负责设置 union 的不同成员
Token &operator=(const string&);
Token &operator=(char);
Token &operator=(int);
Token &operator=(double);
private:
enum { INT, CHAR, DBL, STR } tok; // 判别式
union { // 匿名 union
char cval;
int ival;
double dval;
string sval;
}; // 每个Token对象含有一个该未命名 union类型的未命名成员
// 检查判别式,然后酌情拷贝 union 成员
void copyUnion(const Token&);
};
Token &Token::operator=(const Token &t) {
// 如果此对象的值是 string 而t的值不是,则我们必须释放原来的 string
if (tok == STR && t.tok != STR) sval.~string();
if (tok == STR && t.tok == STR) {
sval = t.sval; // 无须构造一个新 string
} else {
copyUnion(t); // 如果 t.tok 是 STR,则需要构造一个 string
}
tok = t.tok;
return *this;
}
Token &Token::operator=(const string &s) {
if (tok == STR) { // 如果当前存储的是 string,可以直接赋值
sval = s;
} else {
new(&sval) string(s); // 否则需要先构造一个 string
}
tok = STR; // 更新判别式
return *this;
}
Token &Token::operator=(char c) {
if (tok == STR) sval.~string(); // 如果当前存储的是 string,释放它
cval = c; // 为成员赋值
tok = CHAR; // 更新判别式
return *this;
}
Token &Token::operator=(int i) {
if (tok == STR) sval.~string(); // 如果当前存储的是 string,释放它
ival = i; // 为成员赋值
tok = INT; // 更新判别式
return *this;
}
Token &Token::operator=(double d) {
if (tok == STR) sval.~string(); // 如果当前存储的是 string,释放它
dval = d; // 为成员赋值
tok = DBL; // 更新判别式
return *this;
}
void Token::copyUnion(const Token &t) {
switch (t.tok) {
case INT:
ival = t.ival;
break;
case CHAR:
cval = t.cval;
break;
case DBL:
dval = t.dval;
break;
// 要想拷贝一个 string 可以使用定位 new 表达式构造它
case STR:
new(&sval) string(t.sval);
break;
}
}
答:
#include <iostream>
#include <string>
using namespace std;
struct Sales_data {
Sales_data() = default;
Sales_data(const std::string &s) :bookNo(s) {}
Sales_data(const std::string &s, unsigned n, double p) :bookNo(s), units_sold(n), revenue(p*n) {}
std::string isbn() const { return bookNo; }
private:
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
class Token {
public:
// 因为union含有一个string成员,所以Token必须定义拷贝控制成员
Token() : tok(INT), ival{ 0 } { }
Token(const Token &t) : tok(t.tok) { copyUnion(t); }
Token &operator=(const Token&);
// 如果 union 含有一个 string或Sales_data成员,则我们必须销毁它
~Token() {
if (tok == STR) sval.~string();
if (tok == SALE) item.~Sales_data();
}
// 下面的赋值运算符负责设置 union 的不同成员
Token &operator=(const Sales_data&);
Token &operator=(const string&);
Token &operator=(char);
Token &operator=(int);
Token &operator=(double);
private:
enum { INT, CHAR, DBL, STR, SALE } tok; // 判别式
union { // 匿名 union
char cval;
int ival;
double dval;
string sval;
Sales_data item;
}; // 每个Token对象含有一个该未命名 union类型的未命名成员
// 检查判别式,然后酌情拷贝 union 成员
void copyUnion(const Token&);
};
Token &Token::operator=(const Token &t) {
if (this == &t) {
return *this; // 检测自赋值并提前返回
}
// 如果此对象的值是 Sales_data 而t的值不是,则我们必须释放原来的 Sales_data
if (tok == SALE && t.tok != SALE) item.~Sales_data();
// 如果此对象的值是 string 而t的值不是,则我们必须释放原来的 string
if (tok == STR && t.tok != STR) sval.~string();
if (tok == SALE && t.tok == SALE) {
item = t.item; // 无须构造一个新 Sales_data
} else if (tok == STR && t.tok == STR) {
sval = t.sval; // 无须构造一个新 string
}else{
copyUnion(t); // 如果 t.tok 是 STR,则需要构造一个 string
}
tok = t.tok;
return *this;
}
Token &Token::operator=(const Sales_data &s) {
if (tok == SALE) { // 如果当前存储的是 Sales_data,可以直接赋值
item = s;
} else {
new(&item) Sales_data(s); // 否则需要先构造一个 Sales_data
}
tok = SALE; // 更新判别式
return *this;
}
Token &Token::operator=(const string &s) {
if (tok == STR) { // 如果当前存储的是 string,可以直接赋值
sval = s;
} else {
new(&sval) string(s); // 否则需要先构造一个 string
}
tok = STR; // 更新判别式
return *this;
}
Token &Token::operator=(char c) {
if (tok == STR) sval.~string(); // 如果当前存储的是 string,释放它
cval = c; // 为成员赋值
tok = CHAR; // 更新判别式
return *this;
}
Token &Token::operator=(int i) {
if (tok == STR) sval.~string(); // 如果当前存储的是 string,释放它
ival = i; // 为成员赋值
tok = INT; // 更新判别式
return *this;
}
Token &Token::operator=(double d) {
if (tok == STR) sval.~string(); // 如果当前存储的是 string,释放它
dval = d; // 为成员赋值
tok = DBL; // 更新判别式
return *this;
}
void Token::copyUnion(const Token &t) {
switch (t.tok) {
case INT:
ival = t.ival;
break;
case CHAR:
cval = t.cval;
break;
case DBL:
dval = t.dval;
break;
// 要想拷贝一个 string 可以使用定位 new 表达式构造它
case STR:
new(&sval) string(t.sval);
break;
// 要想拷贝一个 Sales_data 可以使用定位 new 表达式构造它
case SALE:
new(&item) Sales_data(t.item);
break;
}
}
答:
// 移动构造函数
Token::Token(Token &&t) noexcept : tok(t.tok) {
switch (tok) {
case INT: ival = t.ival; break;
case CHAR: cval = t.cval; break;
case DBL: dval = t.dval; break;
case STR: new (&sval) string(std::move(t.sval)); break; // 使用std::move来转移string
}
t.tok = INT; // 设置t为无害状态
}
// 移动赋值运算符
Token &Token::operator=(Token &&t) noexcept {
// 自赋值检测
if (this != &t) {
// 如果当前存储的是string,需要先释放它
if (tok == STR) sval.~string();
tok = t.tok;
switch (tok) {
case INT: ival = t.ival; break;
case CHAR: cval = t.cval; break;
case DBL: dval = t.dval; break;
case STR: new (&sval) string(std::move(t.sval)); break; // 转移string
}
t.tok = INT; // 设置t为无害状态
}
return *this;
}
答:
答:
Token &Token::operator=(const string &s) {
if (tok == STR) { // 如果当前存储的是 string,可以直接赋值
sval = s;
} else {
new(&sval) string(s); // 否则需要先构造一个 string
}
tok = STR; // 更新判别式
return *this;
}
Token &Token::operator=(char c) {
if (tok == STR) sval.~string(); // 如果当前存储的是 string,释放它
cval = c; // 为成员赋值
tok = CHAR; // 更新判别式
return *this;
}
Token &Token::operator=(int i) {
if (tok == STR) sval.~string(); // 如果当前存储的是 string,释放它
ival = i; // 为成员赋值
tok = INT; // 更新判别式
return *this;
}
Token &Token::operator=(double d) {
if (tok == STR) sval.~string(); // 如果当前存储的是 string,释放它
dval = d; // 为成员赋值
tok = DBL; // 更新判别式
return *this;
}
extern "C" int compute(int *, int);
extern "C" double compute(double *, double);
答:
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- ovod.cn 版权所有 湘ICP备2023023988号-4
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务