banner
cells

cells

为美好的世界献上 bug

クイズ

Q027#

#include <iostream>

struct A {
    virtual std::ostream &put(std::ostream &o) const {
        return o << 'A';
    }
};

struct B : A {
    virtual std::ostream &put(std::ostream &o) const override {
        return o << 'B';
    }
};

std::ostream &operator<<(std::ostream &o, const A &a) {
    return a.put(o);
}

int main() {
    B b;
    std::cout << b;
}

回答

クリックして回答を表示 B

Q029#

#include <iostream>

struct A {
    A() {
        // std::cout << "A::A()" << std::endl;
        foo();
    }
    virtual ~A() {
        // std::cout << "A::~A()" << std::endl;
        foo();
    }
    virtual void foo() {
        // std::cout << "A::foo()" << std::endl;
        std::cout << "1";
    }
    void bar() {
        // std::cout << "A::bar()" << std::endl;
        foo();
    }
};

struct B : public A {
    virtual void foo() {
        // std::cout << "B::foo()" << std::endl;
        std::cout << "2";
    }
};

int main() {
    B b;
    b.bar();
}

回答

クリックして回答を表示 121

説明

A::foo() は仮想関数であるが、構築および破棄の過程では仮想とは見なされない。

B を構築する前に A を構築する必要があり、A の構築中にはまだ B が構築されていないため、使用してはいけない。A::A() の中の foo() の呼び出しは自然に A::foo() を呼び出す。

オブジェクト b が破棄されるときも同じ問題が発生し、B のデストラクタが呼び出された後に A のデストラクタが呼び出されるため、オブジェクト b の破棄後に B::foo() を使用することはできない。

Q114#

#include <iostream>
#include <memory>
#include <vector>

class C {
public:
    void foo() {
        std::cout << "A";
    }
    void foo() const {
        std::cout << "B";
    }
};

struct S {
    std::vector<C> v;
    std::unique_ptr<C> u;
    C *const p1;
    C const *p2;

    S() : v(1)
        , u(new C())
        , p1(u.get()
        , p2(u.get()) {

    }
};

int main() {
    S s;
    s.v[0].foo();
    s.u->foo();
    s.p1->foo();
    s.p2->foo();

    const S &r = s;
    r.v[0].foo();
    r.u->foo();
    r.p1->foo();
    r.p2->foo();
}

回答

クリックして回答を表示 AAABBAAB

説明

C *const p1 では、p1 ポインターが const 修飾されているため、s オブジェクトのメンバ変数 p1 を呼び出すときには const バージョンの foo が呼び出される。C const *p2 では、*p(C クラス)オブジェクトが const 修飾されているため、s オブジェクトのメンバ変数 p2 を呼び出すときには const バージョンの foo が呼び出される。

rs オブジェクトの定数参照であり、const はメンバ v の動作を変更する。std::vectoroperator[] をオーバーロードしており、定数オブジェクトの場合は定数参照のバージョンを返すため、foo の呼び出しは const バージョンで行われる。

Q360#

// using C++17
#include <iostream>
#include <type_traits>

int main() {
    std::cout << std::is_const_v<const int *>;
    std::cout << std::is_const_v<int *const>;

    std::cout << std::is_const_v<const int[1]>;
    std::cout << std::is_const_v<const int **>;
    std::cout << std::is_const_v<int *const *>;

    std::cout << std::is_const_v<const int(*)[1]>;
    std::cout << std::is_const_v<const int *[1]>;
    std::cout << std::is_const_v<const int[1][1]>;
}

回答

クリックして回答を表示 0110001

説明

const int * は定数整数へのポインターであり、ポインター自体は定数ではないため、結果は false です。

int *const はポインター定数ですので、ポインター自体は定数ですので、結果は true です。

const int[1] は定数整数の配列ですので、配列の要素は定数ですので、結果は true です。

const int **定数ポインターへのポインター です((const int *) *ptr)。ポインター自体は定数ではないため、結果は false です。

int *const *ポインター定数へのポインター です((int *const) *ptr)。ポインター自体は定数ではないため、結果は false です。

const int (*)[1] は定数配列へのポインターですが、ポインター自体は定数ではないため、結果は false です。

const int *[1]定数ポインターの配列 です(const int *ptr[1])。配列の要素は定数ポインターですので、結果は false です。

const int[1][1] は 2 次元配列で、要素は定数ですので、結果は true です。

読み込み中...
ページは、創作者によって署名され、ブロックチェーンに安全に保存されています。