-
C++でfinalクラス(継承禁止クラス)をシミュレートする方法
JavaやC#には、finalクラス(C#ではsealedクラス)と呼ばれる特殊なクラスが存在します。finalクラスは継承が禁止されており、そこから新しいクラスを派生させることはできません。しかし、C++にはこのような機能を直接実現する仕組みはありません。この記事では、C++でfinalクラスをシミュレートするテクニックを紹介します。 finalクラスを実現する仕組み まず、MakeFinalClassという補助クラスを1つ作成します。このクラスのデフォルトコンストラクタはprivateに設定されており、外部からは呼び出せなくなっています。ここがこのテクニックの核心部分です。 そして、メイン
-
C++のexplicitキーワードとは?暗黙の型変換を防ぐ使い方を解説
この記事では、C++におけるexplicitキーワードの効果について詳しく解説します。まずは以下のサンプルコードを見て、出力結果を予想してみてください。 例1:explicitを使わない場合(暗黙の型変換が発生する) #include <iostream> using namespace std; class Point { private: double x, y; public: Point(double a = 0.0, double b = 0.0) : x(a), y(b) { // コンストラクタ }
-
C++におけるプライベートデストラクタの挙動と活用方法
C++では、クラスのデストラクタをprivateとして宣言することが可能です。本記事では、デストラクタをprivateにした場合にどのような挙動になるのか、具体的なサンプルコードとともに詳しく解説します。 プライベートデストラクタとは 通常、デストラクタはpublicとして宣言されますが、あえてprivateにすることで、オブジェクトの生成や破棄の方法を制御できます。まずは基本となるケースから順番に見ていきましょう。 オブジェクトを生成しない場合 次のコードはデストラクタがprivateですが、コンパイルエラーにはなりません。これは、オブジェクトが一切生成されていないためです。 サンプルコード
-
C++における関数オーバーロードとconstキーワードの挙動
C++では関数のオーバーロード(多重定義)が可能です。その中には通常のメンバ関数もあれば、const修飾された定数メンバ関数もあります。本記事では、サンプルプログラムとその実行結果をもとに、定数メンバ関数と通常の関数の違い、そしてオーバーロード時の注意点を解説します。 constメンバ関数と通常の関数のオーバーロード まず、同じ名前の関数を「const版」と「非const版」でオーバーロードした例を見てみましょう。 #include <iostream> using namespace std; class my_class { public: void m
-
C++でmain()関数はオーバーロードできるのか?徹底解説
C++では関数オーバーロード(function overloading)の機能を使うことで、同じ名前でありながら引数の型や個数が異なる複数の関数を定義できます。では、プログラムのエントリーポイントであるmain()関数もオーバーロードできるのでしょうか?結論から言うと、グローバルなmain()関数のオーバーロードはできません。実際にコードで確認してみましょう。main()をオーバーロードしようとするとどうなるか以下のように、引数の異なる複数のmain()関数を定義してみます。サンプルコード#include <iostream> using namespace std; int ma
-
C++入門:名前空間の拡張と無名(匿名)名前空間の使い方
この記事では、C++における名前空間(namespace)の拡張方法と、無名(匿名)名前空間の使い方について解説します。 名前空間の拡張とは C++では、同じ名前の名前空間を複数回定義することができます。最初の定義で一部のメンバーを宣言し、その後に同じ名前空間を再度記述して別のメンバーを追加すると、それらはすべて1つの名前空間として統合されます。これが「名前空間の拡張」です。 拡張された名前空間のすべてのメンバーには、スコープ解決演算子 :: を使ってアクセスできます。 サンプルコード #include <iostream> using namespace std; names
-
C++における継承とfriend(フレンド)関数の関係を解説
C++では、friend(フレンド)関係は継承されないという重要なルールがあります。つまり、親クラスにfriend関数が定義されていても、その子クラスは自動的に同じfriend関数を受け継ぐことはありません。このため、親クラスのプライベートメンバーやプロテクテッドメンバーにはアクセスできても、子クラスのメンバーにはアクセスできないという状況が発生します。以下の例では、display()関数はMyBaseClassのfriendとして宣言されていますが、MyDerivedClassのfriendではないため、コンパイルエラーになります。サンプルコード#include <iostream&g
-
C++で基底クラスのオーバーロードされたメソッドが派生クラスで非表示になる理由と対処法
C++では、同じ名前でも引数の型や個数が異なる複数の関数を定義できる「関数オーバーロード」という便利な機能があります。しかし、継承を扱う際には注意が必要です。基底クラスでオーバーロードされたメソッドがあり、派生クラスでそのうちの1つを再定義すると、基底クラスに存在するその関数のすべてのオーバーロードバージョンが派生クラスから隠されてしまうのです。これは「名前隠蔽(name hiding)」と呼ばれるC++の仕様によるもので、コンパイラはオーバーロード解決の前にスコープ内での名前検索を行い、派生クラスのスコープで該当する名前が見つかった時点で基底クラス側の検索を打ち切るためです。具体例で確認して
-
C++のfesetround()とfegetround()で浮動小数点の丸め方向を制御する方法
この記事では、C++におけるfesetround()とfegetround()という2つの関数について詳しく解説します。これらの関数は、標準ライブラリのcfenvヘッダーに含まれており、浮動小数点演算の丸め動作を細かく制御したい場合に非常に便利です。fesetround()関数とはfesetround()は、指定した浮動小数点数の丸め方向(丸めモード)を、現在の丸め方向として設定するための関数です。rint()やnearbyint()など、C++が提供するさまざまな丸め関数と組み合わせて使用されます。構文は以下の通りです。int fesetround(int round);引数roundには、
-
Bツリーを使ってソートを実現するC++プログラムの解説
本記事では、Bツリー(B-Tree)を使用してソート済みの数列を取得する方法を解説します。Bツリーはn分木(n-ary tree)の一種です。ソートされた順序を得るには、まずBツリーを構築し、そこへ数値を次々と挿入していきます。ここで扱うBツリーは、1つのノードにつき最大5個の要素を保持できます。要素数が上限を超えた場合は、ノードを分割(スプリット)して新しいレベルを形成します。各ノードが保持する要素は最大5個と非常に少ないため、ノード内のソートにはバブルソートを採用しています。扱う要素数が少ないため、全体のパフォーマンスに与える影響はほとんどありません。構築したツリーを走査(トラバース)する
-
無向グラフにオイラー閉路が含まれるかどうかを判定するC++プログラム
オイラー閉路(Euler Circuit)について学ぶには、まずオイラー路(Euler Path)という概念を理解しておく必要があります。オイラー路とは、グラフ内のすべての辺をちょうど一度ずつ通過できる経路のことであり、同じ頂点を複数回通ることは許されます。オイラー閉路は、オイラー路の特別なケースです。オイラー路の始点となる頂点が、そのまま終点の頂点にも接続されており、経路が一つの閉じた周回路となっているものを指します。オイラー閉路の判定条件無向グラフがオイラー閉路を持つかどうかを調べるには、次の2つの条件を確認します。グラフが連結であること ── すべての頂点が辺を介して互いに到達可能である
-
【C++】無向グラフにオイラー路が存在するかどうかを判定する方法
オイラー路(Euler Path)とは、グラフ上のすべての辺をちょうど1回ずつ通る経路のことです。途中で同じ頂点を何度訪れることは許されますが、同じ辺を2回以上使うことはできません。 また、オイラー閉路(Euler Circuit)はオイラー路の特殊なケースで、経路の始点と終点が同じ頂点でつながっているものを指します。 オイラー路が存在するための条件 無向グラフにオイラー路が存在するかどうかは、次の条件で判定できます。 グラフが連結であること 奇数次数の頂点が0個の場合:オイラー閉路が存在します。オイラー閉路はオイラー路の一種でもあります。 奇数次数の頂点がちょうど2個の場合:オイラー路が存
-
有向グラフにオイラー路が存在するか判定するC++プログラム
オイラー路とは オイラー路(Euler Path)とは、グラフのすべての辺をちょうど1回ずつ通ることのできる経路のことです。途中で同じ頂点を何度訪れても問題ありません。なお、オイラー閉路(Euler Circuit)を含むグラフも、始点と終点が一致するオイラー路を持つとみなされるため、本記事では両方を扱います。 有向グラフがオイラー路を持つための条件 有向グラフにオイラー路が存在するかどうかを判定するには、次の3つの条件を確認する必要があります。 出次数 = 入次数 + 1 となる頂点がちょうど1つ存在すること 入次数 = 出次数 + 1 となる頂点がちょうど1つ存在すること 残りのすべての
-
【C++】Linuxでファイルを更新日時順(新しい順・古い順)に一覧表示する方法
この記事では、C++プログラムからLinuxのシェルコマンドを呼び出すことで、カレントディレクトリ内のファイルを「最終更新時刻」を基準に一覧表示する方法を解説します。最近更新されたファイルや、逆に最も古いファイルを簡単に確認できるようになります。 基本となる仕組み 実装の考え方は非常にシンプルです。Linuxには標準でlsコマンドが用意されており、オプションを組み合わせることで希望の順序でファイル情報を取得できます。 ls -l:ファイルを詳細形式(パーミッション、所有者、サイズ、タイムスタンプなど)で一覧表示します。 -t:更新時刻の新しい順(降順)にソートします。 -r:ソート結果を反転
-
C++で文字列の順列の総数を求めるプログラムの作成方法
文字列に含まれる文字は、さまざまな順序で並べ替えることができます。本記事では、与えられた文字列から作成できる順列の数を求める方法を解説します。たとえば「abc」という3文字の文字列の場合、並べ方は 3! = 6 通りあります。つまり、n 文字の文字列であれば、最大で n! 通りの並べ方が存在します。しかし、「aab」のように同じ文字が複数回含まれている場合、単純に 6 通りにはなりません。「aab」の全パターンを書き出してみると、次のようになります。abaaabbaabaaaababaこのうち、(1番目と6番目)、(2番目と5番目)、(3番目と4番目) のペアはそれぞれ同一の並び方です。したが
-
C++のテンプレートとJavaのジェネリクス――仕組みと違いを徹底解説
テンプレートは、特定の型に依存しないコードを記述する「ジェネリックプログラミング」の基盤となる仕組みです。本記事では、C++のテンプレートとJavaのジェネリクスの基本的な使い方をサンプルコードとともに紹介し、両者の主な違いについても詳しく解説します。 C++のテンプレートとは テンプレートは、汎用的なクラスや関数を作成するための「設計図」あるいは「ひな形」となるものです。標準ライブラリのコンテナ、イテレータ、アルゴリズムなどは、いずれもテンプレートの概念を用いて開発されたジェネリックプログラミングの代表例と言えます。 例えば vector のようなコンテナは定義が一つだけですが、vector
-
C++におけるテンプレートの特殊化の基本と実装方法
C++のテンプレートは、汎用的な関数やクラスを作成するための強力な機能です。テンプレートを利用することで、int、char、float などの基本データ型はもちろん、ユーザー定義型を含むあらゆる型に対応したコードを一度の記述で実現できます。しかし、特定の型に対してだけ異なる処理を行いたい場合があります。そんなときに役立つのが「テンプレートの特殊化」です。この記事では、テンプレートの特殊化の仕組みと使い方を、関数テンプレートとクラステンプレートの両方の例を通して詳しく解説します。テンプレートの特殊化とは通常、テンプレートはさまざまな型に対応できる汎用的な定義を行います。一方、テンプレートの特殊化
-
行列式を使って三角形の面積を計算するC++プログラム
この記事では、行列式(デターミナント)を利用して、2次元座標空間上の三角形の面積を求める方法を解説します。ここでは対象となる空間は2次元であると仮定します。行列式による面積の求め方まず、三角形の3つの頂点の座標を1つの行列に配置します。具体的には、x座標を第1列に、y座標を第2列に、そして第3列にはすべて「1」を入れて3×3の行列を作成します。この行列の行列式を計算し、その絶対値の半分が三角形の面積となります。行列式が負の値になった場合でも、絶対値を取れば問題ありません。$$Area\:=\:absolute\:of\begin{pmatrix}\frac{1}{2} \begin{vmatr
-
C++で整数をそれより小さい数の和に分解する方法(分割数)を求めるプログラム
このプログラムでは、ある整数 n が「それより小さい数の総和」として表現できる方法の数、いわゆる分割数(パーティション数)を数えます。例えば n = 7 の場合、「7」「6+1」「5+2」「5+1+1」「4+3」…のように合計14通りの分割が存在します。処理の流れはシンプルです。まず入力として数 n を受け取り、配列の先頭要素を n とします。その後、末尾の要素から順に 1 ずつ取り除いて新しい分割を生成し、分割がひとつ作られるたびにカウンターを増やしていきます。すべての要素が 1 になった時点で処理を終了し、カウントした総数を返します。アルゴリズムpartitionCount(n)入力:整数
-
C++で整数の各桁を拡大表示(ズーム)するプログラムの作り方
この記事では、C++を使って整数の各桁を拡大表示(ズーム)するプログラムを紹介します。ここでの「ズーム」とは、数字を「#」などの記号を使って通常より大きな形で描画することを指します。考え方自体はシンプルですが、0から9までの各数字を大きな形式で一つずつパターン化する必要があります。 ズーム表示の基本的な考え方 各数字は5行×5列のグリッドとして表現します。二重のforループでグリッド全体を走査しながら、行・列の位置関係をもとに条件分岐を行い、「#」と空白のどちらを出力するかを決めます。たとえば「0」なら外枠だけを「#」で囲み、「8」なら上下の横線と左右の縦線を組み合わせて描画するといった具合で