C++の面接でよく出る質問と回答を徹底解説
この記事では、C++の技術面接で頻出する重要な質問をいくつか取り上げ、それぞれのポイントをわかりやすく解説します。面接対策の復習用としても活用できる内容になっています。
C言語とC++の違いは何ですか?
C言語とC++は文法が似ていますが、設計思想やサポートする機能に大きな違いがあります。主な相違点を以下の表にまとめました。
| 項目 | C | C++ |
|---|---|---|
| 開発の経緯 | デニス・リッチーによって1969年頃、AT&Tベル研究所で開発されました。 | ビャーネ・ストロヴストルップによって1979年に開発されました。 |
| 言語タイプ | 手続き型プログラミング言語です。 | 手続き型とオブジェクト指向の両方のプログラミングパラダイムをサポートします。 |
| OOP機能のサポート | OOP(オブジェクト指向プログラミング)の概念をサポートしていないため、ポリモーフィズム、カプセル化、継承には対応していません。 | オブジェクト指向言語であるため、ポリモーフィズム、カプセル化、継承をサポートしています。 |
| データセキュリティ | カプセル化をサポートしていないため、データは自由な実体として扱われ、外部のコードから操作される可能性があります。 | カプセル化によってデータが隠蔽され、データ構造や演算子が意図された通りに使用されることが保証されます。 |
| 駆動方式 | 一般に関数駆動型言語として知られています。 | 一方、C++はオブジェクト駆動型言語として知られています。 |
| サポートされる機能 | 関数や演算子のオーバーロードをサポートしておらず、名前空間や参照変数の機能もありません。 | 関数と演算子のオーバーロードをサポートし、名前空間や参照変数の機能も備えています。 |
ポインタと参照の違いは何ですか?
ポインタと参照はどちらも他の変数を間接的に扱う仕組みですが、以下のような重要な違いがあります。
参照は既存の変数に別名を付けて扱う仕組みである一方、ポインタは変数のアドレスを格納するために使われます。
参照にはNULL値を代入できませんが、ポインタには代入できます。
参照変数は値渡しのように扱えますが、ポインタは参照渡しとして機能します。
参照は宣言時に必ず初期化する必要がありますが、ポインタでは初期化は必須ではありません。
参照は元の変数と同じメモリアドレスを共有しますが、スタック上にいくらかの領域を占有します。一方、ポインタはスタック上に独自のメモリアドレスとサイズを持ちます。
C++における仮想関数とは何ですか?
C++の仮想関数(virtual function)を使うと、基底クラスのポインタを通じて、派生クラスの具体的な型を知らなくても、その派生クラスのメソッドを呼び出せるようになります。仮想関数はコンパイル時ではなく、実行時(遅延バインディング)に解決されます。
基底クラスのメンバ関数を一度 virtual として宣言すると、その基底クラスから派生したすべてのクラスにおいて自動的に仮想関数になります。したがって、派生クラスで仮想関数を再定義する際には、virtual キーワードを改めて付ける必要はありません。
サンプルコード
#include<iostream>
using namespace std;
class B {
public:
virtual void s() {
cout<<" In Base \n";
}
};
class D: public B {
public:
void s() {
cout<<"In Derived \n";
}
};
int main(void) {
D d; // クラスDのオブジェクト
B *b= &d; // dを指すB*型のポインタ
b->s(); // "In Derived" が出力される
return 0;
}
出力結果
In Derived
この例では、基底クラスBのポインタが派生クラスDのオブジェクトを指していますが、s() が仮想関数として宣言されているため、実行時にD側の s() が呼び出されます。
C++におけるthisポインタとは何ですか?
C++のすべてのオブジェクトは、thisポインタと呼ばれる重要なポインタを通じて、自分自身のアドレスにアクセスできます。thisポインタはすべてのメンバ関数に対する暗黙の引数であり、メンバ関数の中では呼び出し元のオブジェクトを参照するために使用できます。
なお、フレンド関数はクラスのメンバではないため、thisポインタを持ちません。thisポインタを持つのはメンバ関数のみです。
次の例で、thisポインタの使い方を確認してみましょう。
サンプルコード
#include <iostream>
using namespace std;
class Box {
public:
// コンストラクタの定義
Box(double l = 2.0, double b = 2.0, double h = 2.0) {
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}
double Volume() {
return length * breadth * height;
}
int compare(Box box) {
return this->Volume() > box.Volume();
}
private:
double length; // 箱の長さ
double breadth; // 箱の幅
double height; // 箱の高さ
};
int main(void) {
Box Box1(3.3, 1.2, 1.5); // Box1を生成
Box Box2(8.5, 6.0, 2.0); // Box2を生成
if(Box1.compare(Box2)) {
cout << "Box2 is smaller than Box1" <<endl;
} else {
cout << "Box2 is equal to or larger than Box1" <<endl;
}
return 0;
}
出力結果
Constructor called. Constructor called. Box2 is equal to or larger than Box1
この例では、compare() メソッド内で this->Volume() を使うことで、呼び出し元オブジェクト(Box1)自身の体積と引数のオブジェクト(Box2)の体積を明確に区別して比較しています。このように、thisポインタは同一クラス内でオブジェクト同士を比較する場面などで非常に役立ちます。
-
C/C++のポインタ演算入門:加算・減算・インクリメント・デクリメントの使い方
C言語におけるポインタ演算とは、ポインタ変数に対して加算や減算、インクリメントなどの算術操作を実行することです。ポインタ演算には主に以下の4種類があります。 加算(+) 減算(-) インクリメント(+1) デクリメント(-1) ポインタ演算の重要な特徴は、移動量が「指し示すデータ型のサイズ × 演算数」で計算される点です。例えば、int型(一般的な環境では4バイト)のポインタに1を加えると、アドレスは1バイトではなく4バイト進みます。さらに5を加えた場合は、4バイト × 5 = 20バイト分アドレスが移動します。 ポインタ演算のサンプルコード 以下は、C言語でポインタ演算を実行する具体的な
-
C++でランダムポインタを持つリンクリストをディープコピーする方法
ランダムポインタを持つリンクリストとはリンクリスト(連結リスト)は代表的な線形データ構造の一つで、各ノードは「ノードが保持する値(データ)」と「次のノードのアドレスを格納するポインタ(next)」という2つの部分で構成されます。本記事では、さらに各ノードがリスト内の別のノードを指す「ランダムポインタ(random)」を持つリンクリストを扱います。このようなリストに対して、元のリストと同じデータ・同じランダムポインタ構造を持つ新しいリストを作成することを、リンクリストの「ディープコピー(Deep Copy)」と呼びます。例入力:出力:5-> 2 -> 3 -> 7 ->4