Loading lang_cpp_04_struct...
struct Init0 { double d; int i; std::string s; };
struct Init1 { double d{12.34}; int i{56}; std::string s{"Init1"}; };
int i=56;) mais celle retenue ici (
int i{56};) est conforme aux recommandations de C++ moderne (voir la règle ES.23 des CppCoreGuideLines).
struct Init2 { double d; int i; std::string s;
Init2() : d{98.76} // member initialiser list , i{54} , s{"Init2"} { // (empty) constructor body } };
struct Init3 { double d; int i; std::string s;
Init3(double in_d, int in_i, std::string in_s) : d{in_d} // member initialiser list , i{in_i} , s{std::move(in_s)} { // (empty) constructor body } };
Init3() : Init3{34.56, 78, "Init3"} // delegating constructor { // (empty) constructor body }
{ 0.0, 0.0, -9.81 }et ne changent pas.
std::array<double, 3>nommé xyz.
{0.0, 0.0, -magnitude}, magnitude étant une constante propre à cette structure valant 9.81.
struct Gravity { static constexpr double magnitude=9.81; // Gravity-specific constant
Gravity() // default constructor : xyz{{0.0, 0.0, -magnitude}} { }
std::array<double, 3> xyz; // data member };
Gravity::Gravity(double x, double y, double z) : Gravity{} // delegating constructor { if(const double sqr_mag=x*x+y*y+z*z; // square magnitude of input vector sqr_mag!=0.0) // overwrite default values only if input vector is not null { const double factor=magnitude/std::sqrt(sqr_mag); xyz={x*factor, y*factor, z*factor}; // adjust magnitude } }
std::ostream & operator<<(std::ostream &output, const Gravity &g);
<<qui sert à combiner une donnée de type std::ostream avec une donnée de type s4prc::Gravity.
<iostream>, représente une abstraction pour désigner un flux de sortie (dans lequel on écrit, comme std::cout ou std::cerr par exemple, voir également cette section).
std::cout << a << b << c;est équivalente à
((std::cout << a) << b) << c;.
std::cout << a;puis
std::cout << b;et enfin
std::cout << c;.
double magnitude(const s4prc::Gravity &g) { return std::sqrt(g.xyz[0]*g.xyz[0]+g.xyz[1]*g.xyz[1]+g.xyz[2]*g.xyz[2]); }
std::array<double, 3>pour représenter l'état du vecteur gravité,
class TypeName // ``struct'' may have been used instead of ``class'' { public: /* Every member in this part of the structure may be accessed by any piece of code in the whole program. */ private: /* Every member in this part of the structure is only accessible from the member functions of this structure. */ };
s4prc::operator<<du fichier gravity.cpp ainsi que la fonction magnitude() du fichier prog.cpp consultent le membre xyz que nous venons de renommer.
double z() const { return xyz_[2]; }
const s4prc::Gravity g0; double value=g0.z();
this->xyz_.
s4prc::operator<<et magnitude() en conséquence.
void set_z(double z) { set_(z, xyz_[2]); }
void Gravity::set_(double value, double &changed) { value=std::max(-magnitude, std::min(magnitude, value)); changed=value; double sqr_remaining=0.0; for(const auto &elem: xyz_) { if(&elem!=&changed) { sqr_remaining+=elem*elem; } } if(sqr_remaining!=0.0) { const double sqr_expected=magnitude*magnitude-value*value; const double factor=std::sqrt(sqr_expected/sqr_remaining); for(auto &elem: xyz_) { if(&elem!=&changed) { elem*=factor; } } } }
class Book { public:
Book(std::vector<std::string> words={});
Book(int word_count, int max_length);
int word_count() const { return int(size(words_)); }
int letter_count() const { return letter_count_; }
const std::vector<std::string> & words() const { return words_; }
private: std::vector<std::string> words_; int letter_count_; };
Book::Book(std::vector<std::string> words) : words_{std::move(words)} , letter_count_{0} { for(const auto &elem: words_) { letter_count_+=int(size(elem)); } }
Book::Book(int wor_count, int max_length) : words_{} , letter_count_{0} { std::default_random_engine rnd_gen{std::random_device{}()}; std::uniform_int_distribution<int> length_distrib{1, max_length}; std::uniform_int_distribution<int> char_distrib{'A', 'Z'}; words_.reserve(word_count); for(int i=0; i<word_count; ++i) { const int length=length_distrib(rnd_gen); std::string s; s.reserve(length); for(int j=0; j<length; ++j) { s+=char(char_distrib(rnd_gen)); } words_.emplace_back(std::move(s)); letter_count_+=length; } }
std::uniform_int_distribution<int>, exposés par le fichier d'en-tête standard
<random>, concernent la génération de valeurs pseudo-aléatoires.
void read(std::string title, s4prc::Book book) // ouch! a huge copy may occur here { std::cout << title << ": " << book.word_count() << " words, " << book.letter_count() << " letters\n"; if(book.word_count()) { std::cout << " " << book.words().front() << " ... " << book.words().back() << '\n'; } }
Book(const Book &) =delete;
s4prc::Book book2{book1};
Book(Book &&) =default;
&&qui spécifie que son unique paramètre est une référence sur une donnée du même type sujette au déplacement (rvalue-reference) : elle désigne une donnée temporaire ou à laquelle nous avons appliqué std::move().
Book & operator=(const Book &) =delete;
Book & operator=(Book &&) =default;
&&qui spécifie que son unique paramètre est une référence sur une donnée du même type sujette au déplacement (rvalue-reference) : elle désigne une donnée temporaire ou à laquelle nous avons appliqué std::move().
~Book() =default;
class SchoolBag { public:
SchoolBag(Book english={}, Book italian={}) : english_{std::move(english)} , italian_{std::move(italian)} { // nothing more to be done }
const Book & english() const { return english_; }
const Book & italian() const { return italian_; }
private: Book english_; Book italian_; };
s4prc::Book english{{"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"}}; s4prc::Book italian{{"uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", "nove", "dieci"}}; s4prc::SchoolBag bag1{std::move(english), std::move(italian)}; s4prc::SchoolBag bag2{std::move(bag1)}; s4prc::SchoolBag bag3; bag3=std::move(bag2); read("english from bag1", bag1.english()); read("italian from bag1", bag1.italian()); read("english from bag2", bag2.english()); read("italian from bag2", bag2.italian()); read("english from bag3", bag3.english()); read("italian from bag3", bag3.italian());
s4prc::SchoolBag bag2{bag1}; bag3=bag2;
//-- provide copy -- SchoolBag(const SchoolBag &rhs); SchoolBag& operator=(const SchoolBag &rhs);
//-- default move is suitable -- SchoolBag(SchoolBag &&) =default; SchoolBag & operator=(SchoolBag &&) =default;
//-- default destruction is suitable -- ~SchoolBag() =default;
SchoolBag::SchoolBag(const SchoolBag &rhs) : english_{rhs.english_.words()} , italian_{rhs.italian_.words()} { // nothing more to be done }
SchoolBag& SchoolBag::operator=(const SchoolBag &rhs) { english_=Book{rhs.english_.words()}; italian_=Book{rhs.italian_.words()}; return *this; }
compiler implicitly declares | ||||||||
---|---|---|---|---|---|---|---|---|
default constructor |
destructor |
copy constructor |
copy assignment |
move constructor |
move assignment |
|||
u s e r d e c l a r e s |
nothing | defaulted |
defaulted |
defaulted |
defaulted |
defaulted |
defaulted |
|
any constructor | not declared |
defaulted |
defaulted |
defaulted |
defaulted |
defaulted |
||
default constructor | user declared |
defaulted |
defaulted |
defaulted |
defaulted |
defaulted |
||
destructor | defaulted |
user declared |
!!! defaulted |
!!! defaulted |
not declared |
not declared |
||
copy constructor | not declared |
defaulted |
user declared |
!!! defaulted |
not declared |
not declared |
||
copy assignment | defaulted |
defaulted |
!!! defaulted |
user declared |
not declared |
not declared |
||
move constructor | not declared |
defaulted |
deleted |
deleted |
user declared |
not declared |
||
move assignment | defaulted |
defaulted |
deleted |
deleted |
not declared |
user declared |
class SysResource { public:
SysResource() : name_{} // no name , res_{nullptr} // no resource { }
explicit SysResource(std::string name) : name_{std::move(name)} , res_{ASK_SYSTEM_FOR_A_NAMED_RESOURCE(data(name_))} { }
~SysResource() { // simply let name_ be destroyed if(res_) // release resource if any { ASK_SYSTEM_TO_RELEASE_THIS_RESOURCE(res_); } }
SysResource(const SysResource &rhs) : name_{rhs.name_} // simply copy this member , res_{ASK_SYSTEM_FOR_A_COPY_OF_THIS_RESOURCE(rhs.res_)} { }
SysResource & operator=(const SysResource &rhs) { if(this!=&rhs) // prevent self copy-assignment { name_=rhs.name_; // simply copy this member if(res_) // release previous resource if any { ASK_SYSTEM_TO_RELEASE_THIS_RESOURCE(res_); } res_=ASK_SYSTEM_FOR_A_COPY_OF_THIS_RESOURCE(rhs.res_); } return *this; // (lhs=rhs) returns the modified lhs }
SysResource(SysResource &&rhs) noexcept : name_{std::move(rhs.name_)} // simply move this member , res_{rhs.res_} // steal resource from rhs { rhs.res_=nullptr; // resource is not owned by rhs anymore }
SysResource & operator=(SysResource &&rhs) noexcept { if(this!=&rhs) // prevent self move-assignment { name_=std::move(rhs.name_); // simply move this member if(res_) // release previous resource if any { ASK_SYSTEM_TO_RELEASE_THIS_RESOURCE(res_); } res_=rhs.res_; // steal resource from rhs rhs.res_=nullptr; // resource is not owned by rhs anymore } return *this; // (lhs=rhs) returns the modified lhs }
void doSomething(int param) { ASK_SYSTEM_TO_USE_THIS_RESOURCE(res_, param); }
int askSomething(int param) const { return ASK_SYSTEM_AN_INFORMATION_ABOUT_THIS_RESOURCE(res_, param); }
private: std::string name_; // assume the system-resource has a name void *res_; // assume the system-resource is accessed through a pointer };
//----------------------------------------------------------------------------
#ifndef S4PRC_INIT_HPP #define S4PRC_INIT_HPP
#include <string>
namespace s4prc {
struct Init0 { double d; int i; std::string s; };
struct Init1 { double d{12.34}; int i{56}; std::string s{"Init1"}; };
struct Init2 { double d; int i; std::string s;
Init2() : d{98.76} // member initialiser list , i{54} , s{"Init2"} { // (empty) constructor body } };
struct Init3 { double d; int i; std::string s;
Init3(double in_d, int in_i, std::string in_s) : d{in_d} // member initialiser list , i{in_i} , s{in_s} { // (empty) constructor body }
#if 1 // enable/disable during experimentation
Init3() : Init3{34.56, 78, "Init3"} // delegating constructor { // (empty) constructor body }
#endif };
} // namespace s4prc
#endif // S4PRC_INIT_HPP
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifndef S4PRC_GRAVITY_HPP #define S4PRC_GRAVITY_HPP
#include <array> #include <iostream>
namespace s4prc {
class Gravity { public:
static constexpr double magnitude=9.81;
Gravity() : xyz_{{0.0, 0.0, -magnitude}} { }
Gravity(double x, double y, double z);
double x() const { return xyz_[0]; }
double y() const { return xyz_[1]; }
double z() const { return xyz_[2]; }
void reverse();
void set_x(double x) { set_(x, xyz_[0]); }
void set_y(double y) { set_(y, xyz_[1]); }
void set_z(double z) { set_(z, xyz_[2]); }
private: void set_(double value, double &changed);
std::array<double, 3> xyz_; };
std::ostream & operator<<(std::ostream &output, const Gravity &g);
Gravity opposite(const Gravity &g);
} // namespace s4prc
#endif // S4PRC_GRAVITY_HPP
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include "gravity.hpp" #include <cmath>
namespace s4prc {
Gravity::Gravity(double x, double y, double z) : Gravity{} // delegating constructor { if(const double sqr_mag=x*x+y*y+z*z; // square magnitude of input vector sqr_mag!=0.0) // overwrite default values only if input vector is not null { const double factor=magnitude/std::sqrt(sqr_mag); xyz_={x*factor, y*factor, z*factor}; // adjust magnitude } }
void Gravity::reverse() { for(auto &elem: xyz_) { elem=-elem; } }
void Gravity::set_(double value, double &changed) { value=std::max(-magnitude, std::min(magnitude, value)); changed=value; double sqr_remaining=0.0; for(const auto &elem: xyz_) { if(&elem!=&changed) { sqr_remaining+=elem*elem; } } if(sqr_remaining!=0.0) { const double sqr_expected=magnitude*magnitude-value*value; const double factor=std::sqrt(sqr_expected/sqr_remaining); for(auto &elem: xyz_) { if(&elem!=&changed) { elem*=factor; } } } }
std::ostream & operator<<(std::ostream &output, const Gravity &g) { return output << "{" << g.x() << ", " << g.y() << ", " << g.z() << "}"; }
Gravity opposite(const Gravity &g) { Gravity r=g; r.reverse(); return r; }
} // namespace s4prc
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifndef S4PRC_BOOK_HPP #define S4PRC_BOOK_HPP
#include <vector> #include <string>
namespace s4prc {
class Book { public:
Book(std::vector<std::string> words={});
Book(int word_count, int max_length);
#if 1 //-- disable copy -- Book(const Book &) =delete; Book & operator=(const Book &) =delete; //-- default move is suitable -- Book(Book &&) =default; Book & operator=(Book &&) =default; //-- default destruction is suitable -- ~Book() =default;
#endif
int word_count() const { return int(size(words_)); }
int letter_count() const { return letter_count_; }
const std::vector<std::string> & words() const { return words_; }
private: std::vector<std::string> words_; int letter_count_; };
} // namespace s4prc
#endif // S4PRC_BOOK_HPP
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include "book.hpp" #include <random>
namespace s4prc {
Book::Book(std::vector<std::string> words) : words_{std::move(words)} , letter_count_{0} { for(const auto &elem: words_) { letter_count_+=int(size(elem)); } }
Book::Book(int word_count, int max_length) : words_{} , letter_count_{0} { std::default_random_engine rnd_gen{std::random_device{}()}; std::uniform_int_distribution<int> length_distrib{1, max_length}; std::uniform_int_distribution<int> char_distrib{'A', 'Z'}; words_.reserve(word_count); for(int i=0; i<word_count; ++i) { const int length=length_distrib(rnd_gen); std::string s; s.reserve(length); for(int j=0; j<length; ++j) { s+=char(char_distrib(rnd_gen)); } words_.emplace_back(std::move(s)); letter_count_+=length; } }
} // namespace s4prc
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifndef S4PRC_SCHOOL_BAG_HPP #define S4PRC_SCHOOL_BAG_HPP
#include "book.hpp"
namespace s4prc {
class SchoolBag { public:
SchoolBag(Book english={}, Book italian={}) : english_{std::move(english)} , italian_{std::move(italian)} { // nothing more to be done }
//-- provide copy -- SchoolBag(const SchoolBag &rhs); SchoolBag& operator=(const SchoolBag &rhs);
//-- default move is suitable -- SchoolBag(SchoolBag &&) =default; SchoolBag & operator=(SchoolBag &&) =default;
//-- default destruction is suitable -- ~SchoolBag() =default;
const Book & english() const { return english_; }
const Book & italian() const { return italian_; }
private: Book english_; Book italian_; };
} // namespace s4prc
#endif // S4PRC_SCHOOL_BAG_HPP
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include "school_bag.hpp"
namespace s4prc {
SchoolBag::SchoolBag(const SchoolBag &rhs) : english_{rhs.english_.words()} , italian_{rhs.italian_.words()} { // nothing more to be done }
SchoolBag& SchoolBag::operator=(const SchoolBag &rhs) { english_=Book{rhs.english_.words()}; italian_=Book{rhs.italian_.words()}; return *this; }
} // namespace s4prc
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include <iostream> #include <cmath> #include "init.hpp" #include "gravity.hpp" #include "book.hpp" #include "school_bag.hpp"
void test_init() { std::cout << "\n~~~~ " << __func__ << "() ~~~~\n"; s4prc::Init0 i0; std::cout << "i0: <" << i0.d << "><" << i0.i << "><" << i0.s << ">\n"; s4prc::Init1 i1; std::cout << "i1: <" << i1.d << "><" << i1.i << "><" << i1.s << ">\n"; s4prc::Init2 i2; std::cout << "i2: <" << i2.d << "><" << i2.i << "><" << i2.s << ">\n"; s4prc::Init3 i3a{123.456, 987, "Hello"}; std::cout << "i3a: <" << i3a.d << "><" << i3a.i << "><" << i3a.s << ">\n"; s4prc::Init3 i3b; std::cout << "i3b: <" << i3b.d << "><" << i3b.i << "><" << i3b.s << ">\n"; }
double magnitude(const s4prc::Gravity &g) { return std::sqrt(g.x()*g.x()+g.y()*g.y()+g.z()*g.z()); }
void test_Gravity() { std::cout << "\n~~~~ " << __func__ << "() ~~~~\n"; const s4prc::Gravity g1; std::cout << "g1=" << g1 << " (mag=" << magnitude(g1) << ")\n"; // g1.reverse(); // non-const member function not allowed on const data s4prc::Gravity g2{1, 2, 3}; std::cout << "g2=" << g2 << " (mag=" << magnitude(g2) << ")\n"; g2.reverse(); std::cout << "reversed g2=" << g2 << " (mag=" << magnitude(g2) << ")\n"; s4prc::Gravity g3=opposite(g1); std::cout << "g3=" << g3 << " (mag=" << magnitude(g3) << ")\n"; for(int i=1; i<=5; ++i) { g3.set_x(i); std::cout << "g3=" << g3 << " (mag=" << magnitude(g3) << ")\n"; g3.set_y(-0.5*i); std::cout << "g3=" << g3 << " (mag=" << magnitude(g3) << ")\n"; g3.set_z(i/3.0); std::cout << "g3=" << g3 << " (mag=" << magnitude(g3) << ")\n"; } }
#define COPY_BOOK 0
#if COPY_BOOK void read(std::string title, s4prc::Book book) // ouch! a huge copy may occur here #else void read(std::string title, const s4prc::Book &book) #endif { std::cout << title << ": " << book.word_count() << " words, " << book.letter_count() << " letters\n"; if(book.word_count()) { std::cout << " " << book.words().front() << " ... " << book.words().back() << '\n'; } }
void test_Book() { std::cout << "\n~~~~ " << __func__ << "() ~~~~\n"; s4prc::Book book1{1'000'000, 20}; #if COPY_BOOK s4prc::Book book2{book1}; #else s4prc::Book book2{std::move(book1)}; #endif read("after init, book1", book1); read("after init, book2", book2); #if COPY_BOOK book1=book2; #else book1=std::move(book2); #endif read("after assign, book1", book1); read("after assign, book2", book2); }
#define COPY_SCHOOLBAG 1
void test_SchoolBag() { std::cout << "\n~~~~ " << __func__ << "() ~~~~\n"; s4prc::Book english{{"one", "two", "three", "four", "five", "six", "seven", "height", "nine", "ten"}}; s4prc::Book italian{{"uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", "nove", "dieci"}}; s4prc::SchoolBag bag1{std::move(english), std::move(italian)}; #if COPY_SCHOOLBAG s4prc::SchoolBag bag2{bag1}; #else s4prc::SchoolBag bag2{std::move(bag1)}; #endif s4prc::SchoolBag bag3; #if COPY_SCHOOLBAG bag3=bag2; #else bag3=std::move(bag2); #endif read("english from bag1", bag1.english()); read("italian from bag1", bag1.italian()); read("english from bag2", bag2.english()); read("italian from bag2", bag2.italian()); read("english from bag3", bag3.english()); read("italian from bag3", bag3.italian()); }
int main() { test_init(); test_Gravity(); test_Book(); test_SchoolBag(); return 0; }
//----------------------------------------------------------------------------