struct Sales_data { string bookNo; unsigned units_sold = { 0 }; double revenue = { 0.0 }; }; int main(int argc, char* argv[]) { Sales_data total; if (cin >> total.bookNo >> total.units_sold >> total.revenue) { Sales_data trans; while (cin >> trans.bookNo >> trans.units_sold >> trans.revenue) { if (total.bookNo == trans.bookNo) { total.revenue += trans.revenue; total.units_sold += trans.units_sold; } else { cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; total = trans; } } cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; } else { std::cerr << "No Data?!" << endl; return -1; } return 0; }
struct Sales_data { string bookNo; unsigned units_sold = { 0 }; double revenue = { 0.0 }; string isbn() { return bookNo; } Sales_data& combine(const Sales_data& rhs) { units_sold += rhs.units_sold; revenue += rhs.revenue; return *this; } };
int main(int argc, char* argv[]) { Sales_data total; if (cin >> total.bookNo >> total.units_sold >> total.revenue) { Sales_data trans; while (cin >> trans.bookNo >> trans.units_sold >> trans.revenue) { if (total.isbn() == trans.isbn()) { total.combine(trans); } else { cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; total = trans; } } cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; } else { std::cerr << "No Data?!" << endl; return -1; } return 0; }
#ifndef PERSON_H_ #define PERSON_H_ #include <string> using std::string; struct Person { string name; string address; }; #endif // !PERSON_H_
struct Person { string name; string address; const string isname() { return name; } const string isaddress() { return address; } };
应该是const的,因为我们不需要修改返回值
Sales_data add(Sales_data& lhs, Sales_data& rhs) { Sales_data sum = lhs; sum.combine(rhs); return sum; } istream &read(istream& is, Sales_data& it) { is >> it.bookNo >> it.units_sold >> it.revenue; return is; } ostream& print(ostream& os, Sales_data& it) { os << it.isbn() << " " << it.units_sold << " " << it.revenue << endl; return os; }
int main(int argc, char* argv[]) { Sales_data total; if (read(cin, total)) { Sales_data trans; while (read(cin,trans)) { if (total.isbn() == trans.isbn()) { total = add(total, trans); } else { print(cout, total); total = trans; } } print(cout, total); } else { std::cerr << "No Data?!" << endl; return -1; } return 0; }
print应该是常量引用的,因为我们不需要修改传入值
struct Person { string name; string address; const string isname() { return name; } const string isaddress() { return address; } }; istream& read(istream& is, Person& it) { is >> it.name >> it.address; return is; } ostream& print(ostream& os, Person& it) { os << it.isname() << " " << it.isaddress() << endl; return os; }
判断读操作对象是否符合要求
struct Sales_data { string bookNo; unsigned units_sold = { 0 }; double revenue = { 0.0 }; string isbn() { return bookNo; } Sales_data& combine(const Sales_data& rhs) { units_sold += rhs.units_sold; revenue += rhs.revenue; return *this; } Sales_data(string bn, unsigned us, double re) :bookNo(bn), units_sold(us), revenue(re) {} Sales_data() = default; };
int main(int argc, char* argv[]) { Sales_data total("",0,0); print(cout, total); return 0; }
struct Sales_data { string bookNo; unsigned units_sold = { 0 }; double revenue = { 0.0 }; string isbn() { return bookNo; } Sales_data& combine(const Sales_data& rhs) { units_sold += rhs.units_sold; revenue += rhs.revenue; return *this; } Sales_data(string bn, unsigned us, double re) :bookNo(bn), units_sold(us), revenue(re) {} Sales_data() = default; Sales_data(istream& is) { read(is, *this); } };
int main(int argc, char* argv[]) { Sales_data total(cin); if (cin) { Sales_data trans(cin); do{ if (total.bookNo == trans.bookNo) { total.revenue += trans.revenue; total.units_sold += trans.units_sold; } else { cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; total = trans; } } while (read(cin, trans)); cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; } else { std::cerr << "No Data?!" << endl; return -1; } return 0; }
Sales_data(string bn, unsigned us, double re) :bookNo(bn), units_sold(us = 0), revenue(re = 0.0) {};
struct Person { string name; string address; const string isname() { return name; } const string isaddress() { return address; } Person() = default; Person(string name, string address) :name(name), address(address) {} };
没有限定。在整个程序内可被访问到的成员应定义在public说明符之后;可以被类的成员访问但不能被使用该类代码访问的应该定义在private说明符之后。
有区别,struct的默认访问权限是public,class的默认访问权限是class
封装:使用函数指针把属性与方法封装到结构体中
成员函数声明成public,成员变量声明成private
类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
优点:能访问私有成员
缺点:破坏封装性
class Sales_data { friend istream& read(istream& is, Sales_data& it); friend ostream& print(ostream& os, Sales_data& it); private: string bookNo; unsigned units_sold = { 0 }; double revenue = { 0.0 }; public: const string& isbn() { return bookNo; } Sales_data& combine(const Sales_data& rhs) { units_sold += rhs.units_sold; revenue += rhs.revenue; return *this; } Sales_data(string bn, unsigned us, double re) :bookNo(bn), units_sold(us = 0), revenue(re = 0.0) {}; Sales_data() = default; Sales_data(istream& is) { read(is, *this); } }; Sales_data add(Sales_data& lhs, Sales_data& rhs) { Sales_data sum = lhs; sum.combine(rhs); return sum; } istream &read(istream& is, Sales_data& it) { is >> it.bookNo >> it.units_sold >> it.revenue; return is; } ostream& print(ostream& os, Sales_data& it) { os << it.isbn() << " " << it.units_sold << " " << it.revenue << endl; return os; }
class Person { friend istream& read(istream& is, Person& it); friend ostream& print(ostream& os, Person& it); private: string name; string address; public: const string isname() { return name; } const string isaddress() { return address; } Person() = default; Person(string name, string address) :name(name), address(address) {} }; istream& read(istream& is, Person& it) { is >> it.name >> it.address; return is; } ostream& print(ostream& os, Person& it) { os << it.isname() << " " << it.isaddress() << endl; return os; }
#ifndef SCREEN_H_ #define SCREEN_H_ #include<string> class Screen { public: using pos = std::string::size_type; private: pos cursor = 0; pos height = 0, width = 0; std::string contents; }; #endif // !SCREEN_H_
class Screen { public: using pos = std::string::size_type; Screen() = default; //Screen(pos ht,pos wd):height(ht),width(wd),contents(ht*wd,‘ ‘){} Screen(pos ht, pos wd,char c=‘ ‘) :height(ht), width(wd), contents(ht* wd, c) {} private: pos cursor = 0; pos height = 0, width = 0; std::string contents; };
可以,因为只有内置类型和可变类型如vector类型,string类型可以依赖于操作的默认版本
在函数体外定义或者类内声明的返回值前添加inline关键字即可
#ifndef SCREEN_H_ #define SCREEN_H_ #include<string> class Screen { public: using pos = std::string::size_type; Screen() = default; //Screen(pos ht,pos wd):height(ht),width(wd),contents(ht*wd,‘ ‘){} Screen(pos ht, pos wd,char c=‘ ‘) :height(ht), width(wd), contents(ht* wd, c) {} Screen& set(char); Screen& set(pos, pos,char); Screen& move(pos, pos); Screen& display(std::ostream& os); const Screen& display(std::ostream& os)const; private: pos cursor = 0; pos height = 0, width = 0; std::string contents; void do_display(std::ostream& os)const { os << contents; } }; inline Screen& Screen::set(char c) { contents[cursor] = c; return *this; } inline Screen& Screen::set(pos row, pos col,char c) { cursor = row * width + col; contents[row * width + col] = c; return *this; } inline Screen& Screen::move(pos row, pos col) { char newc = contents[cursor]; contents[cursor] = contents[row * width + col]; contents[row * width + col] = newc; return *this; } inline Screen& Screen::display(std::ostream& os) { do_display(os); return *this; } inline const Screen& Screen::display(std::ostream& os) const { do_display(os); return *this; } #endif // !SCREEN_H_
若函数返回类型变为Screen,则返回的是对象的副本,函数的操作只能添加于对象的副本上,对象的本身并没有改变。所以两次显示结果会不一样,myScreen不会输出#
#xxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxx
推测正确
1:当需要将一个对象作为整体引用而不是引用对象的一个成员时,使用this,则该函数返回对调用该函数的对象的引用。
2:可以非常明确地指出访问的是调用该函数的对象的成员,且可以在成员函数中使用与数据成员同名的形参。
缺点:不必要使用,代码多余。
class X { Y* y; }; class Y { X* x; };
class Screeen; class Window_mgr { public: using ScreenIndex=std::vector<Screen>::size_type ; void clear(ScreenIndex); private: std::vector<Screen> screens; };
#include "Window_mgr.h" class Screen { public: friend void Window_mgr::clear(ScreenIndex); using pos = std::string::size_type; Screen() = default; //Screen(pos ht,pos wd):height(ht),width(wd),contents(ht*wd,‘ ‘){} Screen(pos ht, pos wd,char c=‘ ‘) :height(ht), width(wd), contents(ht* wd, c) {} Screen set(char); Screen set(pos, pos,char); Screen move(pos, pos); Screen display(std::ostream& os); const Screen display(std::ostream& os)const; private: pos cursor = 0; pos height = 0, width = 0; std::string contents; void do_display(std::ostream& os)const { os << contents; } }; inline Screen Screen::set(char c) { contents[cursor] = c; return *this; } inline Screen Screen::set(pos row, pos col,char c) { cursor = row * width + col; contents[row * width + col] = c; return *this; } inline Screen Screen::move(pos row, pos col) { char newc = contents[cursor]; contents[cursor] = contents[row * width + col]; contents[row * width + col] = newc; return *this; } inline Screen Screen::display(std::ostream& os) { do_display(os); return *this; } inline const Screen Screen::display(std::ostream& os) const { do_display(os); return *this; } inline void Window_mgr::clear(ScreenIndex i) { Screen& s = screens[i]; s.contents = std::string(s.height * s.width, ‘ ‘); }
C++ 成员声明中不允许限定名
Screen::pos Screen::size() const { return height * width; }
Screen类的成员声明中出现pos且在pos的typedef之前的的一律报错。
typedef string Type; Type initval();//外层作用域Money class Exercise { public: typedef double Type;//错误;不能重新定义Money Type setVal(Type);//Type类内匹配 Type initVal();//Type类内匹配,在类内重新声明initVal函数 private: int val; }; Type Exercise::setVal(Type parm) {//外层作用域Type val = parm + initVal(); return val; }
修改后
typedef string Type; Type initval(); class Exercise { public: typedef double Double_type;//修改类内的类型名与外部作用域类型名不相同 Double_type setVal(Double_type); Double_type initVal(); private: int val; }; Exercise::Double_type Exercise::setVal(Double_type parm) { val = parm + initVal(); return val; }
struct X { X(int i, int j) :base(i), rem(base% j) {}//试图使用未初始化的base来初始化rem int rem, base; };
更改成员出现顺序来更改成员的初始化顺序
struct X { X(int i, int j) :base(i), rem(base% j) {} int base, rem; };
Sales_data first_item(cin);//Sales_data(std::istream &is){read(is,*this) };与传入的值相关 int main(int argc, char* argv[]) { Sales_data next;//Sales_data(string s="") :bookNo(s){};cnt = 0, revenue = 0.0 Sales_data last("9-999-99999-9");//Sales_data(string bn, unsigned cnt, double rev) :bookNo(bn), units_sold(cnt), revenue(cnt*rev) {};bookNo = "9-999-99999-9", cnt = 0, revenue = 0.0 }
Sales_data(istream& is = std::cin) { read(is, *this); }
不合法,这样的话接受string的构造函数和接受istream&的构造函数都可以接受无参函数,编译器无法判断要调用哪个函数
#ifndef TREE_H_ #define TREE_H_ #include <vector> #include <string> /*每棵树上都有很多分叉,每个分叉上都可能长着很多片叶子, 所以用Tree来描述树以及树上的枝干,用string来代表每一个枝干上的叶子 */ class Tree { public: using leaf = std::string; Tree(std::vector<Tree> t, std::vector<leaf> l) : trees{ t }, leaves{ l } { } Tree(std::vector<Tree> t, leaf l) : trees{ t }, leaves{ l } { } Tree(Tree t, std::vector<leaf> l) : trees{ t }, leaves{ l } { } Tree(Tree t, leaf l) : trees{ t }, leaves{ l } { } void setTree(Tree t); void setTrees(std::vector<Tree> t); void setLeaf(leaf l); void setLeaves(std::vector<leaf> l); std::vector<Tree> getTrees(); std::vector<leaf> getLeaves(); private: std::vector<Tree> trees; std::vector<leaf> leaves; }; #endif // !TREE_H_
Sales_data(string bn, unsigned us = 0, double re = 0.0) :bookNo(bn), units_sold(us), revenue(re) { std::cout << "Sales_data(string bn, unsigned us = 0, double re = 0.0)" << std::endl;} Sales_data() :Sales_data("") { std::cout << "Sales_data()" << std::endl; } Sales_data(istream& is) :Sales_data() { read(is, *this); std::cout << "Sales_data(istream& is)" << std::endl; }
Sales_data first_item(cin); Sales_data next; Sales_data last("9-999-99999-9");
Sales_data(string bn, unsigned us = 0, double re = 0.0) Sales_data() 1 1 1 Sales_data(istream& is) Sales_data(string bn, unsigned us = 0, double re = 0.0) Sales_data() Sales_data(string bn, unsigned us = 0, double re = 0.0)
class Tree { public: using leaf = std::string; Tree(std::vector<Tree> t, std::vector<leaf> l) : trees(t), leaves(l) { } Tree(std::vector<Tree> t, leaf l) : Tree(t, std::vector<leaf>{l}) { } Tree(Tree t, std::vector<leaf> l) : Tree(std::vector<Tree>{t}, l) { } Tree(Tree t, leaf l) : Tree(std::vector<Tree>{t}, std::vector<leaf>{l}) { } void setTree(Tree t); void setTrees(std::vector<Tree> t); void setLeaf(leaf l); void setLeaves(std::vector<leaf> l); std::vector<Tree> getTrees(); std::vector<leaf> getLeaves(); private: std::vector<Tree> trees; std::vector<leaf> leaves; };
class NoDefault { public: NoDefault(int x) {}; private: }; class C { public: C() :noDefault(0) {}; private: NoDefault noDefault; };
不合法,因为NoDefault类没有默认构造函数,所以不能无参初始化
合法,因为C类有默认构造函数,而且能对成员类初始化
(a)不正确,如果类不提供构造函数,编译器会自动创建一个合成的默认构造函数
(b)不正确,当对象被默认初始化或值初始化都自动执行默认构造函数
(c)不正确,值初始化也需要类提供默认构造函数
(d)不正确,类没有定义任何构造函数的时候,编译器就会自动生成一个默认构造函数
应该。优点是可以避免隐式的类类型转换带来的风险,生成一个隐式转换后的类临时变量,完成操作后就消失了。缺点是用户使用时需要显式的创建临时对象,对用户提高了要求
string null_isbn("9-99-9999-9"); Sales_data item1(null_isbn); // 用string类型的null_isbn直接初始化item1 Sales_data item2("9-99-9999-9"); // 用字符串字面值初始化item2.
Sales_data &combine(Sales_data); // 正常初始化,将s转化成Sales_data类型。 Sales_data &combine(Sales_data&);// 报错,string不能转化为Sales_data类型的引用。 Sales_data &combine(const Sales_data&) const;//报错,常量函数不允许对值做出改变。
explicit Person(istream& in) { read(in, *this); }//只有该构造函数是传入一个参数的
string存在const char*的隐式转换,而vector如果允许隐式转换则会提高理解难度
要使用下面这种方式初始化则必然是聚合类,但是聚合类要求没有类内初始值,所以应该修改为
struct Sales_data { std::string bookNo; unsigned units_sold; double revenue; };
class Debug { public: constexpr Debug(bool h, bool i, bool o) :hw(h), io(i), other(o) {}; constexpr Debug(bool b = true) :Debug(b, b, b) {}; constexpr bool any() { return hw || io || other; } void set_hw(bool b) { hw = b; } void set_io(bool b) { io = b; } void set_other(bool b) { other = b; } private: bool hw; bool io; bool other; };
constexpr函数的返回值和所有形参的类型都必须得是字面值类型,而且函数体中必须有且只有一条return语句,可包含其他语句但不能在运行期起作用,例如;空语句等
所以可以被声明为constexpr
聚合类是字面值常量类,因为聚合类初始化必须使用字面值列表来进行初始化
和类本身相关但不是和类的对象保持联系的成员是类的静态成员,在成员声明前加上static关键字
优点:和类关联但不和类的对象关联,一旦修改所有对象都能使用新值
静态成员和普通成员的区别:不是在创建类的对象时被定义,而是在类的外部定义和初始化,因此静态数据成员可以是不完全类型。类的静态成员属于类本身,在类加载时就会分配内存,可以通过类名直接进行访问。普通成员属于类的对象,只有在类对象产生时才会分配内存。只能通过对象去访问。
class Account { public: void calculate() { amount += amount * interestRate; } static double rate() { return interestRate; } static void rate(double); private: string owner; double amount; static double interestRate; static double initRate(); };
static double rate = 6.5;//成员本身不是常量表达式 static const int vecSize = 20; static std::vector<double> vec(vecSize);//vector对象不能在类内初始化
原文:https://www.cnblogs.com/GodZhuan/p/13910343.html