Part IX
union
union in_or_float {
int i;
float f;
};
struct in_and_float {
int i;
float f;
};
int_or_float dat;
dat.i = 3;
dat.f = 2.0f;
std::cout << f; // 2.0f
std::cout << i; // UB!
int_and_float dat;
dat.i = 3;
dat.f = 2.0f;
std::cout << f; // 2.0f
std::cout << i; // 3
union name {
member1_t member1;
member2_t member2;
member3_t member3;
/* ... */
memberN_t memberN;
};
alignof(name) == max(alignof(member1_t), alignof(member2_t), ...)
sizeof(name) == max(sizeof(member1_t), sizeof(member2_t), ...)
union
union u {
t1 member1;
t2 member2;
t3 member3;
/* ... */
tN memberN;
};
struct s {
t1 member1;
t2 member2;
t3 member3;
/* ... */
tN memberN;
};
sum type
product type
union
union
std::variant<t1, t2, t3, /*...*/ tN>
union u {
t1 member1;
t2 member2;
t3 member3;
/* ... */
tN memberN;
};
std::bit_cast<t2>(t1{})
union
struct vec4 {
union { float x, r, u; };
union { float y, g, v; };
union { float z, b, p; };
union { float w, a, q; };
};
vec4 tex_coords{};
tex_coords.u = 0.5;
tex_coords.v = 0.9;
vec4 position{};
position.x = 13.0;
position.y = -5.0;
position.z = 4.0;
position.w = 1.0;
vec4 color{};
color.r = 0.7;
color.g = 0.2;
color.b = 0.3;
std::cout << color.x;
// 0.7
std::cout << position.a;
// 1.0
std::cout << tex_coords.z;
// 0.0
Aggregate:
int ar[] {3, 1, 4, 1, 5, 9};
std::string s[]{"The", "quick", "brown", "fox"};
namespace vk {
struct ApplicationInfo {
vk::StructureType sType
= StructureType::eApplicationInfo;
const void* pNext{};
const char* pApplicationName{};
uint32_t applicationVersion{};
const char* pEngineName{};
uint32_t engineVersion{};
uint32_t apiVersion{};
};
}
vk::ApplicationInfo applicationInfo{
.pApplicationName = "Space Race Ultimate",
.applicationVersion = 1,
.pEngineName = "Real Engine",
.engineVersion = 1,
.apiVersion = VK_API_VERSION_1_1
};
struct point {
float x, y, z;
}
point ball_position {
2.0, -5.0, 1.0
};
#include <type_traits> std::is_aggregate_v<T>
Base | Derived |
---|---|
public | public |
protected | protected |
private | - |
Base | Derived |
---|---|
public | protected |
protected | protected |
private | - |
Base | Derived |
---|---|
public | private |
protected | private |
private | - |
public
inheritance
private
inheritance
protected
inheritance
class Derived : public Base {
...
};
class Derived : protected Base {
...
};
class Derived : private Base {
...
};
public
inheritance
private
inheritance
protected
inheritance
inherits interface
inherits implementation
(hidden from subclasses)
inherits implementation
(visible to subclasses)
inherit part of interface
class stack : std::vector<int> {
public:
using std::vector<int>::push_back;
using std::vector<int>::emplace_back;
using std::vector<int>::pop_back;
using std::vector<int>::back;
using std::vector<int>::empty;
using std::vector<int>::size;
};
class stack {
private:
std::vector<int> data;
using reference = std::vector<int>::reference;
using const_reference = std::vector<int>::const_reference;
public:
void push(int val) { data.push_back(val); }
template <typename... Args>
reference emplace(Args&&... args) {
return data.emplace_back(std::forward<Args>(args)...);
}
void pop() noexcept { data.pop_back(); }
[[nodiscard]] reference top() noexcept { return data.back(); }
[[nodiscard]] const_reference top() const noexcept { return data.back(); }
[[nodiscard]] bool empty() const noexcept { return data.empty(); }
[[nodiscard]] size_t size() const noexcept { return data.size(); }
};
inherit part of interface
class stack : std::vector<int> {
public:
using std::vector<int>::push_back;
using std::vector<int>::emplace_back;
using std::vector<int>::pop_back;
using std::vector<int>::back;
using std::vector<int>::empty;
using std::vector<int>::size;
};
class stack {
private:
std::vector<int> data;
using reference = std::vector<int>::reference;
using const_reference = std::vector<int>::const_reference;
public:
void push(int val) { data.push_back(val); }
template <typename... Args>
reference emplace(Args&&... args) {
return data.emplace_back(std::forward<Args>(args)...);
}
void pop() noexcept { data.pop_back(); }
[[nodiscard]] reference top() noexcept { return data.back(); }
[[nodiscard]] const_reference top() const noexcept { return data.back(); }
[[nodiscard]] bool empty() const noexcept { return data.empty(); }
[[nodiscard]] size_t size() const noexcept { return data.size(); }
};
prevent upcasting
struct Move {
~Move() {
std::cout << "end"; // not called
}
};
struct Dog {
std::string bark_sound;
void bark() const {
std::cout << bark_sound << '\n';
}
};
struct DancingDog : Dog {
std::vector<Move> dance_moves{Move{}};
void dance() const {
ExitWindowsEx(EWX_POWEROFF|EWX_FORCE, 0);
}
};
{
std::unique_ptr<Dog> pDog(new DancingDog());
} // Dog::~Dog rather than DancingDog::~DancingDog
prevent upcasting
struct Move {
~Move() {
std::cout << "end"; // not called
}
};
struct Dog {
std::string bark_sound;
void bark() const {
std::cout << bark_sound << '\n';
}
};
struct DancingDog : private Dog {
using Dog::bark;
using Dog::bark_sound;
std::vector<Move> dance_moves{Move{}};
void dance() const {
ExitWindowsEx(EWX_POWEROFF|EWX_FORCE, 0);
}
};
{
std::unique_ptr<Dog> pDog(new DancingDog());
// compile error
}
struct loud {
loud() { std::cout << "default ctor\n"; };
loud(const loud&) { std::cout << "copy ctor\n"; };
loud(loud&&) { std::cout << "move ctor\n"; };
~loud() { std::cout << "dtor\n"; };
};
class container {
loud data;
public:
loud& get() { return data; }
const loud& get() const { return data; }
};
container c;
// default ctor
loud& l = c.get();
// -- nothing --
const container cc;
// default ctor
loud& l1 = c.get();
// !! error above !!
const loud& l2 = c.get();
// -- nothing --
struct loud {
loud() { std::cout << "default ctor\n"; };
loud(const loud&) { std::cout << "copy ctor\n"; };
loud(loud&&) { std::cout << "move ctor\n"; };
~loud() { std::cout << "dtor\n"; };
};
class container {
loud data;
public:
loud& get() { return data; }
const loud& get() const { return data; }
};
container c;
// default ctor
loud& l = c.get();
// -- nothing --
const container cc;
// default ctor
loud& l1 = c.get();
// !! error above !!
const loud& l2 = c.get();
// -- nothing --
loud L = container{}.get();
// default ctor
// copy ctor
// dtor
struct loud {
loud() { std::cout << "default ctor\n"; };
loud(const loud&) { std::cout << "copy ctor\n"; };
loud(loud&&) { std::cout << "move ctor\n"; };
~loud() { std::cout << "dtor\n"; };
};
class container {
loud data;
public:
loud& get() & { return data; }
const loud& get() const& { return data; }
loud&& get() && { return std::move(data); }
};
container c;
// default ctor
loud& l = c.get();
// -- nothing --
const container cc;
// default ctor
loud& l1 = c.get();
// !! error above !!
const loud& l2 = c.get();
// -- nothing --
loud L = container{}.get();
// default ctor
// move ctor
// dtor
class C {
private:
inline static std::string s_name = "C";
int m_data;
public:
/* inline */
double member_func(int x, char c) const {
return x * static_cast<float>(c) / 13.0f;
}
};
header file
header file
class C {
private:
static std::string s_name;
int m_data;
public:
double member_func(int x, char c) const;
};
std::string C::s_name = "C";
double C::member_func(int x, char c) const {
return x * static_cast<float>(c) / 13.0f;
}
source file
header file
class widget {
class impl;
std::experimental::propagate_const<std::unique_ptr<impl>> pImpl;
public:
void draw() const;
void draw();
bool shown() const { return true; }
widget(int);
~widget();
widget(widget&&);
widget(const widget&) = delete;
widget& operator=(widget&&);
widget& operator=(const widget&) = delete;
};
class widget::impl {
int n;
public:
void draw(const widget& w) const {
if(w.shown())
std::cout << "drawing a const widget " << n << '\n';
}
void draw(const widget& w) {
if(w.shown())
std::cout << "drawing a non-const widget " << n << '\n';
}
impl(int n) : n(n) {}
};
void widget::draw() const { pImpl->draw(*this); }
void widget::draw() { pImpl->draw(*this); }
widget::widget(int n) : pImpl{std::make_unique<impl>(n)} {}
widget::widget(widget&&) = default;
widget::~widget() = default;
widget& widget::operator=(widget&&) = default;
source file
Part IX
PLAN
RAII
inheritance
virtual
constructor
member initializer list
destructor
default constructor
std::initializer_list
in-class initializer
copy ctor
cpy assign op
move ctor
mv assign op
default members
deleted members
rule of 0
rule of 3/5
smart-ptrs
converting constructor
explicit specifier
is-a relation
has-a relation
public inheritance
protected members
using declaration
final specifier
private & protected inheritance
multiple inheritance
diamond problem
empty base optimization
base method hiding problem (shadowing)
virtual methods
override specifier
dynamic type
RTTI
dynamic_cast
typeid
vtables
by value passing problem (slicing)
pure virtual function
abstract class
misc
friends
nested members
conversion operators
operator overloading
member pointers
unions
std optional
std variant
std any
type ereasure
linkage and static (non-member) functions