質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

4回答

6678閲覧

C#でC++と同じようにポインタを使いたい

legohasiri

総合スコア40

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2020/11/18 15:23

前提・実現したいこと

C++をしばらくやって、C#についてはまだ数日しかやってない初心者です。現在、C#へ、C++で書いたライブラリの移行をしています。
C#にて、次のコードのようなことがしたいのですが、さっぱりわかりません。C/C++でいうところのポインタのようなことがしたいです。

C#

1class hoge{ 2 int n; 3 public hoge(int N){ 4 n=N; 5 } 6 7 public void draw(){ 8 Console.WriteLine("{0}", n); 9 } 10} 11 12public class Hello{ 13 14 public static void Main(){ 15 int x = 0; 16 hoge Hoge = new hoge(x); 17 for(int i=0;i<10;i++){ 18 Hoge.draw(); //0,1,2,3,...と表示されてほしい 19 x++; 20 } 21 } 22}

C++でいうと

C++

1#include <iostream> 2using namespace std; 3class hoge{ 4 int *n; 5public: 6 hoge(int *N){ 7 n = N; 8 } 9 10 void draw(){ 11 cout<<*n<<endl; 12 } 13}; 14 15int main(void){ 16 int x=0; 17 hoge Hoge(&x); 18 for(int i=0;i<10;i++){ 19 Hoge.draw();//1,2,3,... 20 x++; 21 } 22}

がしたいです。

試したこと

hogeの中をunsafeでくくってポインタを使ってみたり、out,refとかもやってみましたが期待通りじゃなかったです。

補足情報(FW/ツールのバージョンなど)

VisualStudio 2019 Community 最新バージョン
.NET Framework 4.7.2
C# 8.0

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

C++ のコードをそのまま C# にすると

C#

1unsafe class hoge 2{ 3 int* n; 4 public hoge(int* N) 5 { 6 n = N; 7 } 8 public void draw() 9 { 10 Console.WriteLine("{0}", *n); 11 } 12} 13 14class Program 15{ 16 unsafe static void Main(string[] args) 17 { 18 int x = 0; 19 hoge Hoge = new hoge(&x); 20 for (int i = 0; i < 10; i++) 21 { 22 Hoge.draw(); 23 x++; 24 } 25 } 26}

のような感じかと思います。(アンセーフコードの許可をチェックしてビルドしてください。)

ですが、C# では値を保持するクラスを作り、そのインスタンスを渡すのが良いと思います。

C#

1class X 2{ 3 public int Value { get; set; } = 0; 4} 5 6class hoge 7{ 8 X n; 9 public hoge(X N) 10 { 11 n = N; 12 } 13 14 public void draw() 15 { 16 Console.WriteLine("{0}", n.Value); 17 } 18} 19 20class Program 21{ 22 static void Main(string[] args) 23 { 24 X x = new X(); 25 hoge Hoge = new hoge(x); 26 for (int i = 0; i < 10; i++) 27 { 28 Hoge.draw(); 29 x.Value++; 30 } 31 } 32}

ちなみに演算子のオーバーロードを行えば、クラス X に対し、演算も可能です。

「演算子のオーバーロード」
https://ufcpp.net/study/csharp/oo_operator.html

投稿2020/11/18 23:58

KOZ6.0

総合スコア2639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

legohasiri

2020/11/19 04:41

皆さん回答ありがとうございました。 いろいろな方法がありどれにしようか考えたのですが、元のクラスにアクセスせずに済む方が都合よかったので、この方法で行きます。
guest

0

こうするのはいかがですか?
複数のクラスで共有する値なら、その値をクラス定義してインスタンスを共有するといいです。

csharp

1using System; 2 3class Hoge { 4 public int X { get; set; } = 0; 5 6 public void Draw() { 7 Console.WriteLine("{0}", x); 8 } 9} 10 11public class Hello { 12 13 public static void Main() { 14 Hoge hoge = new Hoge(); 15 for(int i=0;i<10;i++){ 16 hoge.Draw(); 17 hoge.X++; 18 } 19 } 20}

投稿2020/11/18 15:54

編集2020/11/18 22:56
shiracamus

総合スコア5406

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/11/18 21:47

特別な理由のない限りフィールドはプライベートにしましょう。この場合はプロパティを使うのが適切だと思います。
Zuishin

2020/11/18 22:23

あと、プロパティの命名は通常大文字から始めるようになっていて、小文字の場合、Visual Studio では IDE1006 が出ます。
guest

0

メソッドの引数の値渡し (デフォルト) / 参照渡し (ref 修飾子付与) と、変数の値型 / 参照型をそれらの引数に渡す場合の違いについて調べてみることをお勧めします。

ちなみに、int は値型です。

以下の記事は VB.NET の場合ですが、書き方は違うものの、考え方は C# と同じですので、読んでください。ByVal を値渡し ByRef を参照渡しに読み替えれば理解できると思います。

http://surferonwww.info/BlogEngine/post/2019/01/20/byval-byref-and-value-type-reference-type-in-vbnet.aspx

ref の他に in, out というのがありますが、その違いはググれば参考になる記事が多々ヒットしますので調べてみてください。

【追記】

参照渡し/値渡しを使い分ければできると思って上の回答を書きましたが、勘違いで、質問者さんのコード例ではそれではできなかったです。すみません。

できる案を書いておきます。他の方の回答とダブりますが。

public class Hoge { public int Number { get; set; } public void Draw() { Console.WriteLine(Number); } } class Program { static void Main(string[] args) { Hoge hoge = new Hoge(); hoge.Number = 0; for (int i = 0; i < 10; i++) { hoge.Draw(); hoge.Number++; } } }

投稿2020/11/18 21:56

編集2020/11/19 02:16
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

C#でもポインタを扱う事は出来ますが、マネージドメモリ上のオブジェクトは常に同じアドレスに居るとは限らないので、明示的にアドレスを固定する(GCHandle.Allocやfixedなunsafeポインタを使用する)必要があります。固定している間はガベージコレクターの効率が低下するらしいので、不必要に固定し続けない方が良さそうです。

値型は代入してもコピーが作成されるだけなので、参照を保持するためには参照型のオブジェクトに格納する必要があります。
値型と参照型

解決策は、既に他の回答者の型が回答されているように、クラス側にプロパティを用意してアクセスしたり、値格納用のクラスを作成する方向性で良いかと思います。

ポインタの代替クラスを考えてみます。(あくまでネタです)

C#

1class Pointer<T> 2{ 3 public T Value { get; set; } 4 5 public Pointer() { } 6 7 public Pointer(T value) => Value = value; 8 9 public static implicit operator T(Pointer<T> pVal) => pVal.Value; 10 11 public override string ToString() => Value.ToString(); 12}

提示されているソースを、上記クラスを使用して近い形にしてみます。

c#

1class Hoge 2{ 3 private Pointer<int> _pInt; 4 5 public Hoge(Pointer<int> pInt) 6 { 7 _pInt = pInt; 8 } 9 10 public void Draw() 11 { 12 Console.WriteLine("{0}", _pInt); 13 } 14} 15 16static void Main(string[] args) 17{ 18 var x = new Pointer<int>(0); 19 Hoge hoge = new Hoge(x); 20 for (int i = 0; i < 10; i++) 21 { 22 hoge.Draw(); //0,1,2,3,...と表示されてほしい 23 x.Value++; 24 } 25 26 Console.ReadLine(); 27} 28 29(実行結果) 300 311 322 333 344 355 366 377 388 399

これで一応お望みの動作は実現は出来ました。
ただ、書いておいてなんですが、このようなクラスを使わずとも設計で解決する部分が多いと思うので、
C#への移行を機に、C++側でポインタをメンバにしている箇所があるなら、データの持ち方を見直してみた方が良いでしょう。

投稿2020/11/19 02:48

編集2020/11/20 01:54
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問